@lluc_llull/ui-lib 0.35.0 → 0.36.1
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/fesm2022/lluc_llull-ui-lib-content-split-previewer.mjs +5 -12
- package/fesm2022/lluc_llull-ui-lib-content-split-previewer.mjs.map +1 -1
- package/fesm2022/lluc_llull-ui-lib-content.mjs +4 -11
- package/fesm2022/lluc_llull-ui-lib-content.mjs.map +1 -1
- package/fesm2022/lluc_llull-ui-lib-forms-contact-form.mjs +254 -0
- package/fesm2022/lluc_llull-ui-lib-forms-contact-form.mjs.map +1 -0
- package/fesm2022/lluc_llull-ui-lib-forms.mjs +443 -0
- package/fesm2022/lluc_llull-ui-lib-forms.mjs.map +1 -0
- package/fesm2022/lluc_llull-ui-lib-mapper.mjs +6 -1
- package/fesm2022/lluc_llull-ui-lib-mapper.mjs.map +1 -1
- package/package.json +10 -1
- package/src/lib/styles/main.css +107 -6
- package/styles/main.css +107 -6
- package/types/lluc_llull-ui-lib-forms-contact-form.d.ts +86 -0
- package/types/lluc_llull-ui-lib-forms.d.ts +220 -0
- package/types/lluc_llull-ui-lib-mapper.d.ts +1 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import { Component, EventEmitter, Input, Output, signal } from "@angular/core";
|
|
3
|
+
import * as i1 from "@angular/forms";
|
|
4
|
+
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from "@angular/forms";
|
|
5
|
+
import { FormFieldComponent, FormInputComponent, FormTextareaComponent } from "@lluc_llull/ui-lib/forms";
|
|
6
|
+
import { UiIconComponent, UiImageComponent } from "@lluc_llull/ui-lib/shared";
|
|
7
|
+
var ContactFormComponent = class ContactFormComponent {
|
|
8
|
+
texts;
|
|
9
|
+
privacyUrl = "/es/privacy";
|
|
10
|
+
img = null;
|
|
11
|
+
messageSubmitted = new EventEmitter();
|
|
12
|
+
status = signal("idle", ...ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []);
|
|
13
|
+
submissionError = signal("", ...ngDevMode ? [{ debugName: "submissionError" }] : /* istanbul ignore next */ []);
|
|
14
|
+
submitted = false;
|
|
15
|
+
form = new FormGroup({
|
|
16
|
+
name: new FormControl("", {
|
|
17
|
+
nonNullable: true,
|
|
18
|
+
validators: [
|
|
19
|
+
Validators.required,
|
|
20
|
+
Validators.pattern(/\S/),
|
|
21
|
+
Validators.maxLength(80)
|
|
22
|
+
]
|
|
23
|
+
}),
|
|
24
|
+
surname: new FormControl("", {
|
|
25
|
+
nonNullable: true,
|
|
26
|
+
validators: [Validators.maxLength(100)]
|
|
27
|
+
}),
|
|
28
|
+
email: new FormControl("", {
|
|
29
|
+
nonNullable: true,
|
|
30
|
+
validators: [
|
|
31
|
+
Validators.required,
|
|
32
|
+
Validators.email,
|
|
33
|
+
Validators.maxLength(254)
|
|
34
|
+
]
|
|
35
|
+
}),
|
|
36
|
+
phone: new FormControl("", {
|
|
37
|
+
nonNullable: true,
|
|
38
|
+
validators: [Validators.maxLength(40)]
|
|
39
|
+
}),
|
|
40
|
+
message: new FormControl("", {
|
|
41
|
+
nonNullable: true,
|
|
42
|
+
validators: [
|
|
43
|
+
Validators.required,
|
|
44
|
+
Validators.pattern(/\S/),
|
|
45
|
+
Validators.maxLength(5e3)
|
|
46
|
+
]
|
|
47
|
+
}),
|
|
48
|
+
website: new FormControl("", { nonNullable: true })
|
|
49
|
+
});
|
|
50
|
+
getError(field) {
|
|
51
|
+
const control = this.form.controls[field];
|
|
52
|
+
if (!control.invalid || !control.touched && !this.submitted) return "";
|
|
53
|
+
if (control.hasError("required") || control.hasError("pattern")) return this.texts.requiredError;
|
|
54
|
+
if (control.hasError("email")) return this.texts.emailError;
|
|
55
|
+
if (control.hasError("maxlength")) return this.texts.lengthError;
|
|
56
|
+
return this.texts.invalidError;
|
|
57
|
+
}
|
|
58
|
+
submit() {
|
|
59
|
+
if (this.status() === "sending") return;
|
|
60
|
+
this.submitted = true;
|
|
61
|
+
this.status.set("idle");
|
|
62
|
+
if (this.form.invalid) {
|
|
63
|
+
this.form.markAllAsTouched();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
this.status.set("sending");
|
|
67
|
+
this.messageSubmitted.emit(this.form.getRawValue());
|
|
68
|
+
}
|
|
69
|
+
setSubmissionResult(success, errorMessage = this.texts.error) {
|
|
70
|
+
this.status.set(success ? "success" : "error");
|
|
71
|
+
this.submissionError.set(success ? "" : errorMessage);
|
|
72
|
+
if (success) {
|
|
73
|
+
this.form.reset();
|
|
74
|
+
this.submitted = false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
78
|
+
minVersion: "12.0.0",
|
|
79
|
+
version: "22.2.4",
|
|
80
|
+
ngImport: i0,
|
|
81
|
+
type: ContactFormComponent,
|
|
82
|
+
deps: [],
|
|
83
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
84
|
+
});
|
|
85
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
86
|
+
minVersion: "17.0.0",
|
|
87
|
+
version: "22.2.4",
|
|
88
|
+
type: ContactFormComponent,
|
|
89
|
+
isStandalone: true,
|
|
90
|
+
selector: "lib-contact-form",
|
|
91
|
+
inputs: {
|
|
92
|
+
texts: "texts",
|
|
93
|
+
privacyUrl: "privacyUrl",
|
|
94
|
+
img: "img"
|
|
95
|
+
},
|
|
96
|
+
outputs: { messageSubmitted: "messageSubmitted" },
|
|
97
|
+
host: { styleAttribute: "display: contents" },
|
|
98
|
+
ngImport: i0,
|
|
99
|
+
template: "<section\n class=\"contact-form-section main-grid col-span-full md:col-span-12 md:col-start-1\"\n aria-labelledby=\"contact-form-title\"\n>\n <div class=\"contact-form-heading col-span-full md:col-span-12 md:col-start-1\">\n @if(texts.title) {\n <h2 class=\"title\" id=\"contact-form-title\">{{ texts.title }}</h2> \n }\n @if(texts.intro) {\n <p class=\"text\">{{ texts.intro }}</p>\n }\n </div>\n\n <form\n class=\"contact-form col-span-full\"\n [formGroup]=\"form\"\n (ngSubmit)=\"submit()\"\n [attr.aria-busy]=\"status() === 'sending' ? 'true' : null\"\n novalidate\n >\n <p class=\"contact-form-required-hint col-span-full\">{{ texts.requiredHint }}</p>\n\n <div class=\"contact-form-body main-grid col-span-full\">\n <div class=\"contact-form-grid col-span-full md:col-span-6 md:col-start-1\">\n <lib-form-field\n class=\"col-span-full md:col-span-6\"\n controlId=\"contact-name\"\n [label]=\"texts.name\"\n [required]=\"true\"\n [error]=\"getError('name')\"\n >\n <lib-form-input\n id=\"contact-name\"\n formControlName=\"name\"\n autocomplete=\"given-name\"\n [placeholder]=\"texts.namePlaceholder\"\n [describedBy]=\"getError('name') ? 'contact-name-error' : ''\"\n [invalid]=\"!!getError('name')\"\n [required]=\"true\"\n [maxLength]=\"80\"\n />\n </lib-form-field>\n\n <lib-form-field\n class=\"col-span-full md:col-span-6\"\n controlId=\"contact-surname\"\n [label]=\"texts.surname\"\n >\n <lib-form-input\n id=\"contact-surname\"\n formControlName=\"surname\"\n autocomplete=\"family-name\"\n [placeholder]=\"texts.surnamePlaceholder\"\n [maxLength]=\"100\"\n />\n </lib-form-field>\n\n <lib-form-field\n class=\"col-span-full md:col-span-6\"\n controlId=\"contact-email\"\n [label]=\"texts.email\"\n [required]=\"true\"\n [error]=\"getError('email')\"\n >\n <lib-form-input\n id=\"contact-email\"\n type=\"email\"\n formControlName=\"email\"\n autocomplete=\"email\"\n [placeholder]=\"texts.emailPlaceholder\"\n [describedBy]=\"getError('email') ? 'contact-email-error' : ''\"\n [invalid]=\"!!getError('email')\"\n [required]=\"true\"\n [maxLength]=\"254\"\n />\n </lib-form-field>\n\n <lib-form-field\n class=\"col-span-full md:col-span-6\"\n controlId=\"contact-phone\"\n [label]=\"texts.phone\"\n >\n <lib-form-input\n id=\"contact-phone\"\n type=\"tel\"\n formControlName=\"phone\"\n autocomplete=\"tel\"\n [placeholder]=\"texts.phonePlaceholder\"\n [maxLength]=\"40\"\n />\n </lib-form-field>\n\n <lib-form-field\n class=\"contact-form-field--message col-span-full\"\n controlId=\"contact-message\"\n [label]=\"texts.message\"\n [required]=\"true\"\n [error]=\"getError('message')\"\n >\n <lib-form-textarea\n id=\"contact-message\"\n formControlName=\"message\"\n [placeholder]=\"texts.messagePlaceholder\"\n [describedBy]=\"getError('message') ? 'contact-message-error' : ''\"\n [invalid]=\"!!getError('message')\"\n [required]=\"true\"\n [maxLength]=\"5000\"\n [rows]=\"6\"\n [showCounter]=\"true\"\n />\n </lib-form-field>\n\n </div>\n\n @if (img) {\n <figure class=\"contact-form-image col-span-full md:col-span-6 md:col-start-7\">\n @if (img.publicId) {\n <ui-image\n [publicId]=\"img.publicId\"\n [width]=\"img.width\"\n [height]=\"img.height\"\n [eager]=\"true\"\n />\n } @else {\n <img\n [src]=\"img.url\"\n [alt]=\"img.alt\"\n loading=\"eager\"\n fetchpriority=\"high\"\n [attr.width]=\"img.width || 800\"\n [attr.height]=\"img.height || 600\"\n />\n }\n </figure>\n }\n </div>\n\n <div class=\"contact-form-honeypot\" aria-hidden=\"true\">\n <label for=\"contact-website\">Website</label>\n <input\n id=\"contact-website\"\n type=\"text\"\n formControlName=\"website\"\n tabindex=\"-1\"\n autocomplete=\"off\"\n />\n </div>\n\n <div class=\"contact-form-footer col-span-full\">\n <p class=\"contact-form-privacy col-span-full md:col-span-8\">\n <strong>{{ texts.privacyTitle }}</strong>\n {{ texts.privacyResponsible }}\n {{ texts.privacyPurpose }}\n {{ texts.privacyLegalBasis }}\n {{ texts.privacyRecipients }}\n {{ texts.privacyRetention }}\n {{ texts.privacyRights }}\n {{ texts.privacyLinkLead }}\n <a class=\"contact-form-privacy__link\" [href]=\"privacyUrl\">{{ texts.privacyLink }}</a>\n {{ texts.privacyLinkTail }}\n </p>\n\n <button\n class=\"contact-form-submit col-span-full md:col-span-4\"\n type=\"submit\"\n [disabled]=\"status() === 'sending'\"\n >\n <span>{{ status() === 'sending' ? texts.sending : texts.send }}</span>\n <ui-icon name=\"arrow-up-right\" [size]=\"20\" color=\"currentColor\"></ui-icon>\n </button>\n </div>\n\n @if (status() !== 'idle') {\n <p\n class=\"contact-form-status col-span-full\"\n [class.contact-form-status--success]=\"status() === 'success'\"\n [class.contact-form-status--error]=\"status() === 'error'\"\n [attr.role]=\"status() === 'error' ? 'alert' : 'status'\"\n aria-live=\"polite\"\n >\n {{\n status() === 'sending'\n ? texts.sending\n : status() === 'success'\n ? texts.success\n : submissionError() || texts.error\n }}\n </p>\n }\n </form>\n</section>\n",
|
|
100
|
+
styles: [":host{color:var(--text-primary)}.contact-form-section{padding-top:0!important}.contact-form-heading,.contact-form-required-hint,.contact-form-grid,.contact-form-image,.contact-form-footer{opacity:1;transform:translate(0);transition:opacity .36s ease-out,transform .52s cubic-bezier(.25,1,.5,1)}@starting-style{.contact-form-heading,.contact-form-required-hint,.contact-form-grid,.contact-form-image,.contact-form-footer{opacity:0}}@starting-style{.contact-form-heading,.contact-form-grid,.contact-form-required-hint,.contact-form-footer{transform:translate(-2rem)}}.contact-form-heading{transition-delay:0ms}.contact-form-required-hint{transition-delay:70ms}.contact-form-grid{transition-delay:.12s}.contact-form-image{transition-delay:.17s}@starting-style{.contact-form-image{transform:translate(2rem)}}.contact-form-footer{transition-delay:.22s}.title{text-transform:uppercase}.contact-form-required-hint{font-family:var(--font-base);text-transform:uppercase}.contact-form-body{padding-top:0!important}.contact-form-required-hint{margin:0;color:var(--text-primary-60);font-size:.8rem}.contact-form-image{min-width:0;min-height:100%;margin:0;overflow:hidden}.contact-form-image ui-image,.contact-form-image img{display:block;width:100%;min-height:20rem;object-fit:cover;transform:scaleX(-1)}@media(max-width:1024px){.contact-form-image{display:none}}.contact-form-honeypot{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap}.contact-form-privacy{margin:0;padding-bottom:2rem!important;color:var(--text-primary-60);font-family:var(--font-base);font-size:.82rem;line-height:1.65}.contact-form-privacy strong{color:var(--text-primary-80);font-weight:600}.contact-form-privacy a{color:var(--text-primary);background-image:linear-gradient(var(--text-primary-70),var(--text-primary-70));background-size:100% 1px;background-position:0% 100%;background-repeat:no-repeat;transition:background-size .3s ease-in-out,background-position .3s ease-in-out}.contact-form-privacy a:hover{background-size:0% 1px;background-position:100% 100%;animation:linkMove .4s forwards}@keyframes linkMove{0%{background-size:100% 1px;background-position:0% 100%}50%{background-size:0% 1px;background-position:100% 100%}51%{background-size:0% 1px;background-position:0% 100%}to{background-size:100% 1px;background-position:0% 100%}}.contact-form-footer button{touch-action:manipulation;padding-bottom:2rem;display:inline-flex;min-height:3.5rem;align-items:center;justify-content:space-between;gap:.5rem;border:4px solid var(--border-primary);border-radius:0;padding:.9rem 1.2rem;background:var(--button-primary-bg);color:var(--button-primary-text);cursor:pointer;font-family:var(--font-base);font-size:1rem;text-transform:uppercase;transition:background-color .16s ease,color .16s ease,transform .16s ease;justify-self:end}.contact-form-footer button:hover:not(:disabled){background:var(--button-primary-bg-hover);transform:translateY(-2px)}.contact-form-footer button:active:not(:disabled){transform:translateY(0) scale(.98);transition-duration:.1s}.contact-form-footer button:focus-visible{outline:2px solid var(--color-secondary);outline-offset:4px}.contact-form-footer button:disabled{cursor:wait;opacity:.65}.contact-form-arrow{font-size:1.2rem}.contact-form-status{margin:0;font-family:var(--font-base);line-height:1.5;opacity:1;transform:translateY(0);transition:opacity .18s ease-out,transform .22s cubic-bezier(.22,1,.36,1)}@starting-style{.contact-form-status{opacity:0;transform:translateY(.4rem)}}.contact-form-status--success{color:#18794e}.contact-form-status--error{color:#b42318}.contact-form-submit{max-width:100%}@media(max-width:1024px){.contact-form-submit{width:100%}}@media(prefers-reduced-motion:reduce){.contact-form-heading,.contact-form-required-hint,.contact-form-grid,.contact-form-image,.contact-form-footer{transform:none;transition:opacity .12s ease-out,transform .12s ease-out;transition-delay:0ms}@starting-style{.contact-form-heading,.contact-form-required-hint,.contact-form-grid,.contact-form-image,.contact-form-footer{transform:none}}.contact-form-footer button{transition:none}.contact-form-footer button:active:not(:disabled){transform:none}.contact-form-status{transform:none;transition:opacity .12s ease-out}@starting-style{.contact-form-status{transform:none}}}\n"],
|
|
101
|
+
dependencies: [
|
|
102
|
+
{
|
|
103
|
+
kind: "ngmodule",
|
|
104
|
+
type: ReactiveFormsModule
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
kind: "directive",
|
|
108
|
+
type: i1.ɵNgNoValidate,
|
|
109
|
+
selector: "form:not([ngNoForm]):not([ngNativeValidate])"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
kind: "directive",
|
|
113
|
+
type: i1.DefaultValueAccessor,
|
|
114
|
+
selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
kind: "directive",
|
|
118
|
+
type: i1.NgControlStatus,
|
|
119
|
+
selector: "[formControlName],[ngModel],[formControl]"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
kind: "directive",
|
|
123
|
+
type: i1.NgControlStatusGroup,
|
|
124
|
+
selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
kind: "directive",
|
|
128
|
+
type: i1.RequiredValidator,
|
|
129
|
+
selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",
|
|
130
|
+
inputs: ["required"]
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
kind: "directive",
|
|
134
|
+
type: i1.FormGroupDirective,
|
|
135
|
+
selector: "[formGroup]",
|
|
136
|
+
inputs: ["formGroup"],
|
|
137
|
+
outputs: ["ngSubmit"],
|
|
138
|
+
exportAs: ["ngForm"]
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
kind: "directive",
|
|
142
|
+
type: i1.FormControlName,
|
|
143
|
+
selector: "[formControlName]",
|
|
144
|
+
inputs: [
|
|
145
|
+
"formControlName",
|
|
146
|
+
"disabled",
|
|
147
|
+
"ngModel"
|
|
148
|
+
],
|
|
149
|
+
outputs: ["ngModelChange"]
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
kind: "component",
|
|
153
|
+
type: FormFieldComponent,
|
|
154
|
+
selector: "lib-form-field",
|
|
155
|
+
inputs: [
|
|
156
|
+
"controlId",
|
|
157
|
+
"label",
|
|
158
|
+
"required",
|
|
159
|
+
"hint",
|
|
160
|
+
"error"
|
|
161
|
+
]
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
kind: "component",
|
|
165
|
+
type: FormInputComponent,
|
|
166
|
+
selector: "lib-form-input",
|
|
167
|
+
inputs: [
|
|
168
|
+
"id",
|
|
169
|
+
"type",
|
|
170
|
+
"placeholder",
|
|
171
|
+
"autocomplete",
|
|
172
|
+
"describedBy",
|
|
173
|
+
"maxLength",
|
|
174
|
+
"required",
|
|
175
|
+
"invalid"
|
|
176
|
+
]
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
kind: "component",
|
|
180
|
+
type: FormTextareaComponent,
|
|
181
|
+
selector: "lib-form-textarea",
|
|
182
|
+
inputs: [
|
|
183
|
+
"id",
|
|
184
|
+
"placeholder",
|
|
185
|
+
"describedBy",
|
|
186
|
+
"rows",
|
|
187
|
+
"maxLength",
|
|
188
|
+
"required",
|
|
189
|
+
"invalid",
|
|
190
|
+
"showCounter"
|
|
191
|
+
]
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
kind: "component",
|
|
195
|
+
type: UiImageComponent,
|
|
196
|
+
selector: "ui-image",
|
|
197
|
+
inputs: [
|
|
198
|
+
"publicId",
|
|
199
|
+
"cloudName",
|
|
200
|
+
"transformations",
|
|
201
|
+
"eager",
|
|
202
|
+
"width",
|
|
203
|
+
"height"
|
|
204
|
+
]
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
kind: "component",
|
|
208
|
+
type: UiIconComponent,
|
|
209
|
+
selector: "ui-icon",
|
|
210
|
+
inputs: [
|
|
211
|
+
"name",
|
|
212
|
+
"size",
|
|
213
|
+
"color"
|
|
214
|
+
]
|
|
215
|
+
}
|
|
216
|
+
]
|
|
217
|
+
});
|
|
218
|
+
};
|
|
219
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
220
|
+
minVersion: "12.0.0",
|
|
221
|
+
version: "22.2.4",
|
|
222
|
+
ngImport: i0,
|
|
223
|
+
type: ContactFormComponent,
|
|
224
|
+
decorators: [{
|
|
225
|
+
type: Component,
|
|
226
|
+
args: [{
|
|
227
|
+
selector: "lib-contact-form",
|
|
228
|
+
standalone: true,
|
|
229
|
+
imports: [
|
|
230
|
+
ReactiveFormsModule,
|
|
231
|
+
FormFieldComponent,
|
|
232
|
+
FormInputComponent,
|
|
233
|
+
FormTextareaComponent,
|
|
234
|
+
UiImageComponent,
|
|
235
|
+
UiIconComponent
|
|
236
|
+
],
|
|
237
|
+
host: { style: "display: contents" },
|
|
238
|
+
template: "<section\n class=\"contact-form-section main-grid col-span-full md:col-span-12 md:col-start-1\"\n aria-labelledby=\"contact-form-title\"\n>\n <div class=\"contact-form-heading col-span-full md:col-span-12 md:col-start-1\">\n @if(texts.title) {\n <h2 class=\"title\" id=\"contact-form-title\">{{ texts.title }}</h2> \n }\n @if(texts.intro) {\n <p class=\"text\">{{ texts.intro }}</p>\n }\n </div>\n\n <form\n class=\"contact-form col-span-full\"\n [formGroup]=\"form\"\n (ngSubmit)=\"submit()\"\n [attr.aria-busy]=\"status() === 'sending' ? 'true' : null\"\n novalidate\n >\n <p class=\"contact-form-required-hint col-span-full\">{{ texts.requiredHint }}</p>\n\n <div class=\"contact-form-body main-grid col-span-full\">\n <div class=\"contact-form-grid col-span-full md:col-span-6 md:col-start-1\">\n <lib-form-field\n class=\"col-span-full md:col-span-6\"\n controlId=\"contact-name\"\n [label]=\"texts.name\"\n [required]=\"true\"\n [error]=\"getError('name')\"\n >\n <lib-form-input\n id=\"contact-name\"\n formControlName=\"name\"\n autocomplete=\"given-name\"\n [placeholder]=\"texts.namePlaceholder\"\n [describedBy]=\"getError('name') ? 'contact-name-error' : ''\"\n [invalid]=\"!!getError('name')\"\n [required]=\"true\"\n [maxLength]=\"80\"\n />\n </lib-form-field>\n\n <lib-form-field\n class=\"col-span-full md:col-span-6\"\n controlId=\"contact-surname\"\n [label]=\"texts.surname\"\n >\n <lib-form-input\n id=\"contact-surname\"\n formControlName=\"surname\"\n autocomplete=\"family-name\"\n [placeholder]=\"texts.surnamePlaceholder\"\n [maxLength]=\"100\"\n />\n </lib-form-field>\n\n <lib-form-field\n class=\"col-span-full md:col-span-6\"\n controlId=\"contact-email\"\n [label]=\"texts.email\"\n [required]=\"true\"\n [error]=\"getError('email')\"\n >\n <lib-form-input\n id=\"contact-email\"\n type=\"email\"\n formControlName=\"email\"\n autocomplete=\"email\"\n [placeholder]=\"texts.emailPlaceholder\"\n [describedBy]=\"getError('email') ? 'contact-email-error' : ''\"\n [invalid]=\"!!getError('email')\"\n [required]=\"true\"\n [maxLength]=\"254\"\n />\n </lib-form-field>\n\n <lib-form-field\n class=\"col-span-full md:col-span-6\"\n controlId=\"contact-phone\"\n [label]=\"texts.phone\"\n >\n <lib-form-input\n id=\"contact-phone\"\n type=\"tel\"\n formControlName=\"phone\"\n autocomplete=\"tel\"\n [placeholder]=\"texts.phonePlaceholder\"\n [maxLength]=\"40\"\n />\n </lib-form-field>\n\n <lib-form-field\n class=\"contact-form-field--message col-span-full\"\n controlId=\"contact-message\"\n [label]=\"texts.message\"\n [required]=\"true\"\n [error]=\"getError('message')\"\n >\n <lib-form-textarea\n id=\"contact-message\"\n formControlName=\"message\"\n [placeholder]=\"texts.messagePlaceholder\"\n [describedBy]=\"getError('message') ? 'contact-message-error' : ''\"\n [invalid]=\"!!getError('message')\"\n [required]=\"true\"\n [maxLength]=\"5000\"\n [rows]=\"6\"\n [showCounter]=\"true\"\n />\n </lib-form-field>\n\n </div>\n\n @if (img) {\n <figure class=\"contact-form-image col-span-full md:col-span-6 md:col-start-7\">\n @if (img.publicId) {\n <ui-image\n [publicId]=\"img.publicId\"\n [width]=\"img.width\"\n [height]=\"img.height\"\n [eager]=\"true\"\n />\n } @else {\n <img\n [src]=\"img.url\"\n [alt]=\"img.alt\"\n loading=\"eager\"\n fetchpriority=\"high\"\n [attr.width]=\"img.width || 800\"\n [attr.height]=\"img.height || 600\"\n />\n }\n </figure>\n }\n </div>\n\n <div class=\"contact-form-honeypot\" aria-hidden=\"true\">\n <label for=\"contact-website\">Website</label>\n <input\n id=\"contact-website\"\n type=\"text\"\n formControlName=\"website\"\n tabindex=\"-1\"\n autocomplete=\"off\"\n />\n </div>\n\n <div class=\"contact-form-footer col-span-full\">\n <p class=\"contact-form-privacy col-span-full md:col-span-8\">\n <strong>{{ texts.privacyTitle }}</strong>\n {{ texts.privacyResponsible }}\n {{ texts.privacyPurpose }}\n {{ texts.privacyLegalBasis }}\n {{ texts.privacyRecipients }}\n {{ texts.privacyRetention }}\n {{ texts.privacyRights }}\n {{ texts.privacyLinkLead }}\n <a class=\"contact-form-privacy__link\" [href]=\"privacyUrl\">{{ texts.privacyLink }}</a>\n {{ texts.privacyLinkTail }}\n </p>\n\n <button\n class=\"contact-form-submit col-span-full md:col-span-4\"\n type=\"submit\"\n [disabled]=\"status() === 'sending'\"\n >\n <span>{{ status() === 'sending' ? texts.sending : texts.send }}</span>\n <ui-icon name=\"arrow-up-right\" [size]=\"20\" color=\"currentColor\"></ui-icon>\n </button>\n </div>\n\n @if (status() !== 'idle') {\n <p\n class=\"contact-form-status col-span-full\"\n [class.contact-form-status--success]=\"status() === 'success'\"\n [class.contact-form-status--error]=\"status() === 'error'\"\n [attr.role]=\"status() === 'error' ? 'alert' : 'status'\"\n aria-live=\"polite\"\n >\n {{\n status() === 'sending'\n ? texts.sending\n : status() === 'success'\n ? texts.success\n : submissionError() || texts.error\n }}\n </p>\n }\n </form>\n</section>\n",
|
|
239
|
+
styles: [":host{color:var(--text-primary)}.contact-form-section{padding-top:0!important}.contact-form-heading,.contact-form-required-hint,.contact-form-grid,.contact-form-image,.contact-form-footer{opacity:1;transform:translate(0);transition:opacity .36s ease-out,transform .52s cubic-bezier(.25,1,.5,1)}@starting-style{.contact-form-heading,.contact-form-required-hint,.contact-form-grid,.contact-form-image,.contact-form-footer{opacity:0}}@starting-style{.contact-form-heading,.contact-form-grid,.contact-form-required-hint,.contact-form-footer{transform:translate(-2rem)}}.contact-form-heading{transition-delay:0ms}.contact-form-required-hint{transition-delay:70ms}.contact-form-grid{transition-delay:.12s}.contact-form-image{transition-delay:.17s}@starting-style{.contact-form-image{transform:translate(2rem)}}.contact-form-footer{transition-delay:.22s}.title{text-transform:uppercase}.contact-form-required-hint{font-family:var(--font-base);text-transform:uppercase}.contact-form-body{padding-top:0!important}.contact-form-required-hint{margin:0;color:var(--text-primary-60);font-size:.8rem}.contact-form-image{min-width:0;min-height:100%;margin:0;overflow:hidden}.contact-form-image ui-image,.contact-form-image img{display:block;width:100%;min-height:20rem;object-fit:cover;transform:scaleX(-1)}@media(max-width:1024px){.contact-form-image{display:none}}.contact-form-honeypot{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap}.contact-form-privacy{margin:0;padding-bottom:2rem!important;color:var(--text-primary-60);font-family:var(--font-base);font-size:.82rem;line-height:1.65}.contact-form-privacy strong{color:var(--text-primary-80);font-weight:600}.contact-form-privacy a{color:var(--text-primary);background-image:linear-gradient(var(--text-primary-70),var(--text-primary-70));background-size:100% 1px;background-position:0% 100%;background-repeat:no-repeat;transition:background-size .3s ease-in-out,background-position .3s ease-in-out}.contact-form-privacy a:hover{background-size:0% 1px;background-position:100% 100%;animation:linkMove .4s forwards}@keyframes linkMove{0%{background-size:100% 1px;background-position:0% 100%}50%{background-size:0% 1px;background-position:100% 100%}51%{background-size:0% 1px;background-position:0% 100%}to{background-size:100% 1px;background-position:0% 100%}}.contact-form-footer button{touch-action:manipulation;padding-bottom:2rem;display:inline-flex;min-height:3.5rem;align-items:center;justify-content:space-between;gap:.5rem;border:4px solid var(--border-primary);border-radius:0;padding:.9rem 1.2rem;background:var(--button-primary-bg);color:var(--button-primary-text);cursor:pointer;font-family:var(--font-base);font-size:1rem;text-transform:uppercase;transition:background-color .16s ease,color .16s ease,transform .16s ease;justify-self:end}.contact-form-footer button:hover:not(:disabled){background:var(--button-primary-bg-hover);transform:translateY(-2px)}.contact-form-footer button:active:not(:disabled){transform:translateY(0) scale(.98);transition-duration:.1s}.contact-form-footer button:focus-visible{outline:2px solid var(--color-secondary);outline-offset:4px}.contact-form-footer button:disabled{cursor:wait;opacity:.65}.contact-form-arrow{font-size:1.2rem}.contact-form-status{margin:0;font-family:var(--font-base);line-height:1.5;opacity:1;transform:translateY(0);transition:opacity .18s ease-out,transform .22s cubic-bezier(.22,1,.36,1)}@starting-style{.contact-form-status{opacity:0;transform:translateY(.4rem)}}.contact-form-status--success{color:#18794e}.contact-form-status--error{color:#b42318}.contact-form-submit{max-width:100%}@media(max-width:1024px){.contact-form-submit{width:100%}}@media(prefers-reduced-motion:reduce){.contact-form-heading,.contact-form-required-hint,.contact-form-grid,.contact-form-image,.contact-form-footer{transform:none;transition:opacity .12s ease-out,transform .12s ease-out;transition-delay:0ms}@starting-style{.contact-form-heading,.contact-form-required-hint,.contact-form-grid,.contact-form-image,.contact-form-footer{transform:none}}.contact-form-footer button{transition:none}.contact-form-footer button:active:not(:disabled){transform:none}.contact-form-status{transform:none;transition:opacity .12s ease-out}@starting-style{.contact-form-status{transform:none}}}\n"]
|
|
240
|
+
}]
|
|
241
|
+
}],
|
|
242
|
+
propDecorators: {
|
|
243
|
+
texts: [{
|
|
244
|
+
type: Input,
|
|
245
|
+
args: [{ required: true }]
|
|
246
|
+
}],
|
|
247
|
+
privacyUrl: [{ type: Input }],
|
|
248
|
+
img: [{ type: Input }],
|
|
249
|
+
messageSubmitted: [{ type: Output }]
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
export { ContactFormComponent };
|
|
253
|
+
|
|
254
|
+
//# sourceMappingURL=lluc_llull-ui-lib-forms-contact-form.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lluc_llull-ui-lib-forms-contact-form.mjs","names":[],"sources":["../../../projects/ui-lib/forms/contact-form/contact-form.component.ts","../../../projects/ui-lib/forms/contact-form/contact-form.component.html"],"sourcesContent":["import { Component, EventEmitter, Input, Output, signal } from '@angular/core';\nimport { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';\nimport {\n FormFieldComponent,\n FormInputComponent,\n FormTextareaComponent,\n} from '@lluc_llull/ui-lib/forms';\nimport { UiLibImageI } from '@lluc_llull/ui-lib/interfaces';\nimport { UiImageComponent } from '@lluc_llull/ui-lib/shared';\nimport { ContactFormSubmissionI, ContactFormTextsI } from './contact-form.interface';\nimport { UiIconComponent } from '@lluc_llull/ui-lib/shared';\n\ntype ContactField = 'name' | 'email' | 'message';\ntype ContactFormStatus = 'idle' | 'sending' | 'success' | 'error';\n\n@Component({\n selector: 'lib-contact-form',\n standalone: true,\n imports: [\n ReactiveFormsModule,\n FormFieldComponent,\n FormInputComponent,\n FormTextareaComponent,\n UiImageComponent,\n UiIconComponent\n ],\n templateUrl: './contact-form.component.html',\n styleUrl: './contact-form.component.scss',\n host: {\n style: 'display: contents',\n },\n})\nexport class ContactFormComponent {\n @Input({ required: true }) texts!: ContactFormTextsI;\n @Input() privacyUrl = '/es/privacy';\n @Input() img: UiLibImageI | null = null;\n @Output() readonly messageSubmitted = new EventEmitter<ContactFormSubmissionI>();\n\n readonly status = signal<ContactFormStatus>('idle');\n readonly submissionError = signal('');\n submitted = false;\n\n readonly form = new FormGroup({\n name: new FormControl('', {\n nonNullable: true,\n validators: [Validators.required, Validators.pattern(/\\S/), Validators.maxLength(80)],\n }),\n surname: new FormControl('', {\n nonNullable: true,\n validators: [Validators.maxLength(100)],\n }),\n email: new FormControl('', {\n nonNullable: true,\n validators: [Validators.required, Validators.email, Validators.maxLength(254)],\n }),\n phone: new FormControl('', {\n nonNullable: true,\n validators: [Validators.maxLength(40)],\n }),\n message: new FormControl('', {\n nonNullable: true,\n validators: [Validators.required, Validators.pattern(/\\S/), Validators.maxLength(5000)],\n }),\n website: new FormControl('', { nonNullable: true }),\n });\n\n getError(field: ContactField): string {\n const control = this.form.controls[field];\n if (!control.invalid || (!control.touched && !this.submitted)) return '';\n if (control.hasError('required') || control.hasError('pattern')) {\n return this.texts.requiredError;\n }\n if (control.hasError('email')) return this.texts.emailError;\n if (control.hasError('maxlength')) return this.texts.lengthError;\n return this.texts.invalidError;\n }\n\n submit(): void {\n if (this.status() === 'sending') return;\n\n this.submitted = true;\n this.status.set('idle');\n if (this.form.invalid) {\n this.form.markAllAsTouched();\n return;\n }\n\n this.status.set('sending');\n this.messageSubmitted.emit(this.form.getRawValue());\n }\n\n setSubmissionResult(success: boolean, errorMessage = this.texts.error): void {\n this.status.set(success ? 'success' : 'error');\n this.submissionError.set(success ? '' : errorMessage);\n if (success) {\n this.form.reset();\n this.submitted = false;\n }\n }\n}\n","<section\n class=\"contact-form-section main-grid col-span-full md:col-span-12 md:col-start-1\"\n aria-labelledby=\"contact-form-title\"\n>\n <div class=\"contact-form-heading col-span-full md:col-span-12 md:col-start-1\">\n @if(texts.title) {\n <h2 class=\"title\" id=\"contact-form-title\">{{ texts.title }}</h2> \n }\n @if(texts.intro) {\n <p class=\"text\">{{ texts.intro }}</p>\n }\n </div>\n\n <form\n class=\"contact-form col-span-full\"\n [formGroup]=\"form\"\n (ngSubmit)=\"submit()\"\n [attr.aria-busy]=\"status() === 'sending' ? 'true' : null\"\n novalidate\n >\n <p class=\"contact-form-required-hint col-span-full\">{{ texts.requiredHint }}</p>\n\n <div class=\"contact-form-body main-grid col-span-full\">\n <div class=\"contact-form-grid col-span-full md:col-span-6 md:col-start-1\">\n <lib-form-field\n class=\"col-span-full md:col-span-6\"\n controlId=\"contact-name\"\n [label]=\"texts.name\"\n [required]=\"true\"\n [error]=\"getError('name')\"\n >\n <lib-form-input\n id=\"contact-name\"\n formControlName=\"name\"\n autocomplete=\"given-name\"\n [placeholder]=\"texts.namePlaceholder\"\n [describedBy]=\"getError('name') ? 'contact-name-error' : ''\"\n [invalid]=\"!!getError('name')\"\n [required]=\"true\"\n [maxLength]=\"80\"\n />\n </lib-form-field>\n\n <lib-form-field\n class=\"col-span-full md:col-span-6\"\n controlId=\"contact-surname\"\n [label]=\"texts.surname\"\n >\n <lib-form-input\n id=\"contact-surname\"\n formControlName=\"surname\"\n autocomplete=\"family-name\"\n [placeholder]=\"texts.surnamePlaceholder\"\n [maxLength]=\"100\"\n />\n </lib-form-field>\n\n <lib-form-field\n class=\"col-span-full md:col-span-6\"\n controlId=\"contact-email\"\n [label]=\"texts.email\"\n [required]=\"true\"\n [error]=\"getError('email')\"\n >\n <lib-form-input\n id=\"contact-email\"\n type=\"email\"\n formControlName=\"email\"\n autocomplete=\"email\"\n [placeholder]=\"texts.emailPlaceholder\"\n [describedBy]=\"getError('email') ? 'contact-email-error' : ''\"\n [invalid]=\"!!getError('email')\"\n [required]=\"true\"\n [maxLength]=\"254\"\n />\n </lib-form-field>\n\n <lib-form-field\n class=\"col-span-full md:col-span-6\"\n controlId=\"contact-phone\"\n [label]=\"texts.phone\"\n >\n <lib-form-input\n id=\"contact-phone\"\n type=\"tel\"\n formControlName=\"phone\"\n autocomplete=\"tel\"\n [placeholder]=\"texts.phonePlaceholder\"\n [maxLength]=\"40\"\n />\n </lib-form-field>\n\n <lib-form-field\n class=\"contact-form-field--message col-span-full\"\n controlId=\"contact-message\"\n [label]=\"texts.message\"\n [required]=\"true\"\n [error]=\"getError('message')\"\n >\n <lib-form-textarea\n id=\"contact-message\"\n formControlName=\"message\"\n [placeholder]=\"texts.messagePlaceholder\"\n [describedBy]=\"getError('message') ? 'contact-message-error' : ''\"\n [invalid]=\"!!getError('message')\"\n [required]=\"true\"\n [maxLength]=\"5000\"\n [rows]=\"6\"\n [showCounter]=\"true\"\n />\n </lib-form-field>\n\n </div>\n\n @if (img) {\n <figure class=\"contact-form-image col-span-full md:col-span-6 md:col-start-7\">\n @if (img.publicId) {\n <ui-image\n [publicId]=\"img.publicId\"\n [width]=\"img.width\"\n [height]=\"img.height\"\n [eager]=\"true\"\n />\n } @else {\n <img\n [src]=\"img.url\"\n [alt]=\"img.alt\"\n loading=\"eager\"\n fetchpriority=\"high\"\n [attr.width]=\"img.width || 800\"\n [attr.height]=\"img.height || 600\"\n />\n }\n </figure>\n }\n </div>\n\n <div class=\"contact-form-honeypot\" aria-hidden=\"true\">\n <label for=\"contact-website\">Website</label>\n <input\n id=\"contact-website\"\n type=\"text\"\n formControlName=\"website\"\n tabindex=\"-1\"\n autocomplete=\"off\"\n />\n </div>\n\n <div class=\"contact-form-footer col-span-full\">\n <p class=\"contact-form-privacy col-span-full md:col-span-8\">\n <strong>{{ texts.privacyTitle }}</strong>\n {{ texts.privacyResponsible }}\n {{ texts.privacyPurpose }}\n {{ texts.privacyLegalBasis }}\n {{ texts.privacyRecipients }}\n {{ texts.privacyRetention }}\n {{ texts.privacyRights }}\n {{ texts.privacyLinkLead }}\n <a class=\"contact-form-privacy__link\" [href]=\"privacyUrl\">{{ texts.privacyLink }}</a>\n {{ texts.privacyLinkTail }}\n </p>\n\n <button\n class=\"contact-form-submit col-span-full md:col-span-4\"\n type=\"submit\"\n [disabled]=\"status() === 'sending'\"\n >\n <span>{{ status() === 'sending' ? texts.sending : texts.send }}</span>\n <ui-icon name=\"arrow-up-right\" [size]=\"20\" color=\"currentColor\"></ui-icon>\n </button>\n </div>\n\n @if (status() !== 'idle') {\n <p\n class=\"contact-form-status col-span-full\"\n [class.contact-form-status--success]=\"status() === 'success'\"\n [class.contact-form-status--error]=\"status() === 'error'\"\n [attr.role]=\"status() === 'error' ? 'alert' : 'status'\"\n aria-live=\"polite\"\n >\n {{\n status() === 'sending'\n ? texts.sending\n : status() === 'success'\n ? texts.success\n : submissionError() || texts.error\n }}\n </p>\n }\n </form>\n</section>\n"],"mappings":"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"}
|