easy-forms-core 1.1.8 → 1.1.9
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/README.md +1 -0
- package/dist/easy-form.d.ts +12 -2
- package/dist/easy-form.js +203 -1
- package/dist/easy-form.js.map +1 -1
- package/dist/index.d.ts +13 -3
- package/dist/index.js +203 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -470,6 +470,7 @@ Puedes sobrescribir cualquier estilo usando las clases CSS del componente. Todas
|
|
|
470
470
|
- Arrays dinámicos
|
|
471
471
|
- **Rows (filas horizontales)** - Agrupa campos en filas
|
|
472
472
|
- **Slots (row)** - Inserta contenido HTML en posiciones concretas del formulario
|
|
473
|
+
- **Campo password** - Opciones `showToggle` (ver/ocultar) y `characterSeparated` (entrada por caracteres, tipo OTP)
|
|
473
474
|
- **Datos iniciales** - Carga valores iniciales desde datos externos
|
|
474
475
|
- Componentes visuales personalizables
|
|
475
476
|
- Eventos de submit, change y error
|
package/dist/easy-form.d.ts
CHANGED
|
@@ -125,7 +125,17 @@ interface BaseField {
|
|
|
125
125
|
* Campo de texto
|
|
126
126
|
*/
|
|
127
127
|
interface TextField extends BaseField {
|
|
128
|
-
type: 'text' | 'email'
|
|
128
|
+
type: 'text' | 'email';
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Campo password (con opciones de visibilidad y modo carácter separado)
|
|
132
|
+
*/
|
|
133
|
+
interface PasswordField extends BaseField {
|
|
134
|
+
type: 'password';
|
|
135
|
+
/** Mostrar botón para alternar visibilidad del texto */
|
|
136
|
+
showToggle?: boolean;
|
|
137
|
+
/** Modo carácter separado: true = longitud por defecto 6, number = cantidad de cajas */
|
|
138
|
+
characterSeparated?: boolean | number;
|
|
129
139
|
}
|
|
130
140
|
/**
|
|
131
141
|
* Campo numérico
|
|
@@ -277,7 +287,7 @@ interface OTPField extends BaseField {
|
|
|
277
287
|
/**
|
|
278
288
|
* Unión de todos los tipos de campos
|
|
279
289
|
*/
|
|
280
|
-
type Field = TextField | NumberField | TextareaField | SelectField | CheckboxField | RadioField | SwitchField | DateField | FileField | ArrayField | GroupField | RowField | CustomField | QuantityField | AccordionSelectField | ImageGridSelectField | OTPField;
|
|
290
|
+
type Field = TextField | PasswordField | NumberField | TextareaField | SelectField | CheckboxField | RadioField | SwitchField | DateField | FileField | ArrayField | GroupField | RowField | CustomField | QuantityField | AccordionSelectField | ImageGridSelectField | OTPField;
|
|
281
291
|
/**
|
|
282
292
|
* Step para formularios wizard
|
|
283
293
|
*/
|
package/dist/easy-form.js
CHANGED
|
@@ -689,6 +689,62 @@ function getBaseStyles(colors) {
|
|
|
689
689
|
.easy-form-otp-input:invalid {
|
|
690
690
|
border-color: var(--easy-form-error);
|
|
691
691
|
}
|
|
692
|
+
/* Password inner (input + toggle) */
|
|
693
|
+
.easy-form-password-inner {
|
|
694
|
+
display: flex;
|
|
695
|
+
align-items: center;
|
|
696
|
+
gap: 0.5rem;
|
|
697
|
+
}
|
|
698
|
+
.easy-form-password-inner .easy-form-password-input {
|
|
699
|
+
flex: 1;
|
|
700
|
+
min-width: 0;
|
|
701
|
+
}
|
|
702
|
+
.easy-form-password-toggle {
|
|
703
|
+
flex-shrink: 0;
|
|
704
|
+
display: inline-flex;
|
|
705
|
+
align-items: center;
|
|
706
|
+
justify-content: center;
|
|
707
|
+
padding: 0.35rem;
|
|
708
|
+
background: transparent;
|
|
709
|
+
border: 1px solid var(--easy-form-border);
|
|
710
|
+
border-radius: 4px;
|
|
711
|
+
cursor: pointer;
|
|
712
|
+
color: var(--easy-form-text);
|
|
713
|
+
}
|
|
714
|
+
.easy-form-password-toggle:hover {
|
|
715
|
+
border-color: var(--easy-form-primary);
|
|
716
|
+
color: var(--easy-form-primary);
|
|
717
|
+
}
|
|
718
|
+
.easy-form-password-toggle:focus {
|
|
719
|
+
outline: none;
|
|
720
|
+
box-shadow: 0 0 0 2px var(--easy-form-primary);
|
|
721
|
+
}
|
|
722
|
+
/* Password car\xE1cter separado */
|
|
723
|
+
.easy-form-password-separated {
|
|
724
|
+
display: flex;
|
|
725
|
+
flex-wrap: nowrap;
|
|
726
|
+
gap: 0.5rem;
|
|
727
|
+
align-items: center;
|
|
728
|
+
}
|
|
729
|
+
.easy-form-password-separated-input {
|
|
730
|
+
width: 2.5rem;
|
|
731
|
+
height: 2.5rem;
|
|
732
|
+
text-align: center;
|
|
733
|
+
font-size: 1.25rem;
|
|
734
|
+
border: 2px solid var(--easy-form-border);
|
|
735
|
+
border-radius: 4px;
|
|
736
|
+
transition: border-color 0.2s ease;
|
|
737
|
+
}
|
|
738
|
+
.easy-form-password-separated-input:focus {
|
|
739
|
+
border-color: var(--easy-form-primary);
|
|
740
|
+
outline: none;
|
|
741
|
+
}
|
|
742
|
+
.easy-form-password-separated-toggle {
|
|
743
|
+
flex-shrink: 0;
|
|
744
|
+
}
|
|
745
|
+
.easy-form-password-separated-toggle .easy-form-password-toggle {
|
|
746
|
+
padding: 0.35rem;
|
|
747
|
+
}
|
|
692
748
|
/* Loading Overlay (sobre el formulario) */
|
|
693
749
|
.easy-form-loading-overlay {
|
|
694
750
|
position: absolute;
|
|
@@ -4196,13 +4252,159 @@ var OTPInput = class extends BaseInput {
|
|
|
4196
4252
|
}
|
|
4197
4253
|
};
|
|
4198
4254
|
|
|
4255
|
+
// src/components/inputs/password-input.ts
|
|
4256
|
+
var DEFAULT_SEPARATED_LENGTH = 6;
|
|
4257
|
+
function eyeSvg(visible) {
|
|
4258
|
+
if (visible) {
|
|
4259
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/><line x1="1" y1="1" x2="23" y2="23"/></svg>`;
|
|
4260
|
+
}
|
|
4261
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>`;
|
|
4262
|
+
}
|
|
4263
|
+
var PasswordInput = class extends BaseInput {
|
|
4264
|
+
constructor() {
|
|
4265
|
+
super(...arguments);
|
|
4266
|
+
this.inputs = [];
|
|
4267
|
+
this.visible = false;
|
|
4268
|
+
}
|
|
4269
|
+
get passwordField() {
|
|
4270
|
+
return this.field;
|
|
4271
|
+
}
|
|
4272
|
+
render() {
|
|
4273
|
+
const pf = this.passwordField;
|
|
4274
|
+
const useSeparated = !!pf.characterSeparated;
|
|
4275
|
+
const length = useSeparated ? typeof pf.characterSeparated === "number" ? pf.characterSeparated : DEFAULT_SEPARATED_LENGTH : 0;
|
|
4276
|
+
if (useSeparated) {
|
|
4277
|
+
return this.createFieldContainer(this.renderSeparated(length));
|
|
4278
|
+
}
|
|
4279
|
+
return this.createFieldContainer(this.renderSingle());
|
|
4280
|
+
}
|
|
4281
|
+
renderSingle() {
|
|
4282
|
+
const pf = this.passwordField;
|
|
4283
|
+
const showToggle = !!pf.showToggle;
|
|
4284
|
+
const input = document.createElement("input");
|
|
4285
|
+
input.type = "password";
|
|
4286
|
+
input.value = this.value ?? "";
|
|
4287
|
+
input.id = this.getFieldId();
|
|
4288
|
+
this.applyCommonProps(input);
|
|
4289
|
+
if (this.field.placeholder) input.placeholder = this.field.placeholder;
|
|
4290
|
+
input.addEventListener("input", (e) => {
|
|
4291
|
+
this.onChange(e.target.value);
|
|
4292
|
+
});
|
|
4293
|
+
input.addEventListener("blur", () => this.onBlur());
|
|
4294
|
+
if (!showToggle) {
|
|
4295
|
+
return input;
|
|
4296
|
+
}
|
|
4297
|
+
const wrapper = document.createElement("div");
|
|
4298
|
+
wrapper.className = "easy-form-password-inner";
|
|
4299
|
+
input.classList.add("easy-form-password-input");
|
|
4300
|
+
wrapper.appendChild(input);
|
|
4301
|
+
const btn = document.createElement("button");
|
|
4302
|
+
btn.type = "button";
|
|
4303
|
+
btn.className = "easy-form-password-toggle";
|
|
4304
|
+
btn.setAttribute("aria-label", "Mostrar contrase\xF1a");
|
|
4305
|
+
btn.innerHTML = eyeSvg(false);
|
|
4306
|
+
btn.addEventListener("click", () => {
|
|
4307
|
+
this.visible = !this.visible;
|
|
4308
|
+
input.type = this.visible ? "text" : "password";
|
|
4309
|
+
btn.setAttribute("aria-label", this.visible ? "Ocultar contrase\xF1a" : "Mostrar contrase\xF1a");
|
|
4310
|
+
btn.innerHTML = eyeSvg(this.visible);
|
|
4311
|
+
});
|
|
4312
|
+
wrapper.appendChild(btn);
|
|
4313
|
+
return wrapper;
|
|
4314
|
+
}
|
|
4315
|
+
renderSeparated(length) {
|
|
4316
|
+
const pf = this.passwordField;
|
|
4317
|
+
const showToggle = !!pf.showToggle;
|
|
4318
|
+
const value = this.value ?? "";
|
|
4319
|
+
const valueString = String(value).slice(0, length);
|
|
4320
|
+
const container = document.createElement("div");
|
|
4321
|
+
container.className = "easy-form-password-separated";
|
|
4322
|
+
for (let i = 0; i < length; i++) {
|
|
4323
|
+
const input = document.createElement("input");
|
|
4324
|
+
input.type = "password";
|
|
4325
|
+
input.maxLength = 1;
|
|
4326
|
+
input.className = "easy-form-password-separated-input";
|
|
4327
|
+
input.setAttribute("aria-label", `Car\xE1cter ${i + 1} de ${length}`);
|
|
4328
|
+
if (valueString[i]) input.value = valueString[i];
|
|
4329
|
+
this.applyCommonProps(input);
|
|
4330
|
+
input.id = i === 0 ? this.getFieldId() : `${this.getFieldId()}-${i}`;
|
|
4331
|
+
if (i > 0) input.removeAttribute("name");
|
|
4332
|
+
const currentIndex = i;
|
|
4333
|
+
input.addEventListener("input", (e) => {
|
|
4334
|
+
const target = e.target;
|
|
4335
|
+
const val = target.value;
|
|
4336
|
+
if (val && currentIndex < length - 1) {
|
|
4337
|
+
this.inputs[currentIndex + 1].focus();
|
|
4338
|
+
}
|
|
4339
|
+
this.updateSeparatedValue();
|
|
4340
|
+
});
|
|
4341
|
+
input.addEventListener("keydown", (e) => {
|
|
4342
|
+
if (e.key === "Backspace" && !e.target.value && currentIndex > 0) {
|
|
4343
|
+
this.inputs[currentIndex - 1].focus();
|
|
4344
|
+
this.inputs[currentIndex - 1].value = "";
|
|
4345
|
+
this.updateSeparatedValue();
|
|
4346
|
+
}
|
|
4347
|
+
if (e.key === "ArrowLeft" && currentIndex > 0) {
|
|
4348
|
+
e.preventDefault();
|
|
4349
|
+
this.inputs[currentIndex - 1].focus();
|
|
4350
|
+
}
|
|
4351
|
+
if (e.key === "ArrowRight" && currentIndex < length - 1) {
|
|
4352
|
+
e.preventDefault();
|
|
4353
|
+
this.inputs[currentIndex + 1].focus();
|
|
4354
|
+
}
|
|
4355
|
+
});
|
|
4356
|
+
input.addEventListener("paste", (e) => {
|
|
4357
|
+
e.preventDefault();
|
|
4358
|
+
const text = (e.clipboardData || window.clipboardData)?.getData("text") || "";
|
|
4359
|
+
const chars = text.slice(0, length - currentIndex).split("");
|
|
4360
|
+
for (let j = 0; j < chars.length && currentIndex + j < length; j++) {
|
|
4361
|
+
this.inputs[currentIndex + j].value = chars[j];
|
|
4362
|
+
}
|
|
4363
|
+
const nextIdx = Math.min(currentIndex + chars.length, length - 1);
|
|
4364
|
+
this.inputs[nextIdx].focus();
|
|
4365
|
+
this.updateSeparatedValue();
|
|
4366
|
+
});
|
|
4367
|
+
input.addEventListener("focus", (e) => e.target.select());
|
|
4368
|
+
input.addEventListener("blur", () => this.onBlur());
|
|
4369
|
+
this.inputs.push(input);
|
|
4370
|
+
container.appendChild(input);
|
|
4371
|
+
}
|
|
4372
|
+
if (showToggle) {
|
|
4373
|
+
const toggleWrap = document.createElement("div");
|
|
4374
|
+
toggleWrap.className = "easy-form-password-separated-toggle";
|
|
4375
|
+
const btn = document.createElement("button");
|
|
4376
|
+
btn.type = "button";
|
|
4377
|
+
btn.className = "easy-form-password-toggle";
|
|
4378
|
+
btn.setAttribute("aria-label", "Mostrar contrase\xF1a");
|
|
4379
|
+
btn.innerHTML = eyeSvg(false);
|
|
4380
|
+
btn.addEventListener("click", () => {
|
|
4381
|
+
this.visible = !this.visible;
|
|
4382
|
+
const type = this.visible ? "text" : "password";
|
|
4383
|
+
this.inputs.forEach((inp) => {
|
|
4384
|
+
inp.type = type;
|
|
4385
|
+
});
|
|
4386
|
+
btn.setAttribute("aria-label", this.visible ? "Ocultar contrase\xF1a" : "Mostrar contrase\xF1a");
|
|
4387
|
+
btn.innerHTML = eyeSvg(this.visible);
|
|
4388
|
+
});
|
|
4389
|
+
toggleWrap.appendChild(btn);
|
|
4390
|
+
container.appendChild(toggleWrap);
|
|
4391
|
+
}
|
|
4392
|
+
return container;
|
|
4393
|
+
}
|
|
4394
|
+
updateSeparatedValue() {
|
|
4395
|
+
const value = this.inputs.map((inp) => inp.value).join("");
|
|
4396
|
+
this.onChange(value || null);
|
|
4397
|
+
}
|
|
4398
|
+
};
|
|
4399
|
+
|
|
4199
4400
|
// src/components/inputs/index.ts
|
|
4200
4401
|
function createInput(field, value, error, onChange, onBlur) {
|
|
4201
4402
|
switch (field.type) {
|
|
4202
4403
|
case "text":
|
|
4203
4404
|
case "email":
|
|
4204
|
-
case "password":
|
|
4205
4405
|
return new TextInput(field, value, error, onChange, onBlur).render();
|
|
4406
|
+
case "password":
|
|
4407
|
+
return new PasswordInput(field, value, error, onChange, onBlur).render();
|
|
4206
4408
|
case "number":
|
|
4207
4409
|
return new NumberInput(field, value, error, onChange, onBlur).render();
|
|
4208
4410
|
case "textarea":
|