easy-forms-core 1.1.6 → 1.1.7
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 +63 -0
- package/dist/easy-form.d.ts +15 -0
- package/dist/easy-form.js +96 -7
- package/dist/easy-form.js.map +1 -1
- package/dist/index.d.ts +15 -0
- package/dist/index.js +96 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -108,6 +108,68 @@ form.schema = {
|
|
|
108
108
|
}
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
+
### Slots con inserción por fila (row)
|
|
112
|
+
|
|
113
|
+
Puedes insertar contenido HTML personalizado en posiciones concretas del formulario usando **hijos directos** del componente con el atributo `row`. El índice es 0-based (cada campo o fila del schema cuenta como una posición). Usa `row="-1"` para insertar al final, antes del botón de envío.
|
|
114
|
+
|
|
115
|
+
| Valor | Comportamiento |
|
|
116
|
+
|--------|-----------------|
|
|
117
|
+
| `row="0"` | Antes del primer campo |
|
|
118
|
+
| `row="1"` | Entre el primer y el segundo campo |
|
|
119
|
+
| `row="-1"` | Al final del formulario (antes del submit) |
|
|
120
|
+
| Sin `row` o valor inválido | Se trata como `-1` (al final) |
|
|
121
|
+
|
|
122
|
+
**HTML Vanilla**
|
|
123
|
+
|
|
124
|
+
```html
|
|
125
|
+
<easy-form id="form">
|
|
126
|
+
<div row="0">Mensaje al inicio</div>
|
|
127
|
+
<div row="2">Mensaje después del segundo campo</div>
|
|
128
|
+
<div row="-1">Mensaje al final</div>
|
|
129
|
+
</easy-form>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
```javascript
|
|
133
|
+
import 'easy-forms-core'
|
|
134
|
+
|
|
135
|
+
const form = document.querySelector('#form')
|
|
136
|
+
form.schema = {
|
|
137
|
+
fields: [
|
|
138
|
+
{ type: 'text', name: 'name', label: 'Nombre' },
|
|
139
|
+
{ type: 'email', name: 'email', label: 'Email' },
|
|
140
|
+
{ type: 'textarea', name: 'message', label: 'Mensaje' }
|
|
141
|
+
]
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**React**
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
import 'easy-forms-core'
|
|
149
|
+
|
|
150
|
+
function MyForm() {
|
|
151
|
+
return (
|
|
152
|
+
<easy-form schema={{ fields: [...] }}>
|
|
153
|
+
<div row="0">Contenido al inicio</div>
|
|
154
|
+
<div row="-1">Contenido al final</div>
|
|
155
|
+
</easy-form>
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Vue**
|
|
161
|
+
|
|
162
|
+
```vue
|
|
163
|
+
<template>
|
|
164
|
+
<easy-form :schema="schema">
|
|
165
|
+
<div row="0">Contenido al inicio</div>
|
|
166
|
+
<div row="-1">Contenido al final</div>
|
|
167
|
+
</easy-form>
|
|
168
|
+
</template>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Los slots son solo visuales: los inputs dentro de un slot **no** forman parte del estado ni del envío del formulario. En formularios por pasos (wizard), el índice `row` es relativo al paso actual.
|
|
172
|
+
|
|
111
173
|
### React
|
|
112
174
|
|
|
113
175
|
```tsx
|
|
@@ -407,6 +469,7 @@ Puedes sobrescribir cualquier estilo usando las clases CSS del componente. Todas
|
|
|
407
469
|
- Formularios anidados
|
|
408
470
|
- Arrays dinámicos
|
|
409
471
|
- **Rows (filas horizontales)** - Agrupa campos en filas
|
|
472
|
+
- **Slots (row)** - Inserta contenido HTML en posiciones concretas del formulario
|
|
410
473
|
- **Datos iniciales** - Carga valores iniciales desde datos externos
|
|
411
474
|
- Componentes visuales personalizables
|
|
412
475
|
- Eventos de submit, change y error
|
package/dist/easy-form.d.ts
CHANGED
|
@@ -361,6 +361,11 @@ declare class EasyForm extends BrowserHTMLElement {
|
|
|
361
361
|
private isRendering;
|
|
362
362
|
private attemptsLock;
|
|
363
363
|
private lockCountdownInterval;
|
|
364
|
+
/**
|
|
365
|
+
* Plantillas de slots basados en atributo `row` en el light DOM.
|
|
366
|
+
* Se inicializan una sola vez y se clonan en cada render.
|
|
367
|
+
*/
|
|
368
|
+
private slotTemplates;
|
|
364
369
|
static get observedAttributes(): string[];
|
|
365
370
|
constructor();
|
|
366
371
|
/**
|
|
@@ -449,6 +454,16 @@ declare class EasyForm extends BrowserHTMLElement {
|
|
|
449
454
|
* Retorna un objeto con los valores preservados
|
|
450
455
|
*/
|
|
451
456
|
private preserveCurrentValues;
|
|
457
|
+
/**
|
|
458
|
+
* Inicializa las plantillas de slots a partir del light DOM.
|
|
459
|
+
* Cualquier hijo directo que sea HTMLElement se considera slot; si tiene atributo `row` se usa para la posición, si no se inserta al final (-1).
|
|
460
|
+
*/
|
|
461
|
+
private initializeSlotTemplates;
|
|
462
|
+
/**
|
|
463
|
+
* Obtiene clones de slots agrupados por índice de fila efectivo.
|
|
464
|
+
* Cualquier valor inválido o fuera de rango se normaliza a -1 (final del formulario).
|
|
465
|
+
*/
|
|
466
|
+
private getSlotClonesByRow;
|
|
452
467
|
/**
|
|
453
468
|
* Renderiza campos normales
|
|
454
469
|
*/
|
package/dist/easy-form.js
CHANGED
|
@@ -4763,6 +4763,11 @@ var EasyForm = class extends BrowserHTMLElement {
|
|
|
4763
4763
|
this.isRendering = false;
|
|
4764
4764
|
this.attemptsLock = null;
|
|
4765
4765
|
this.lockCountdownInterval = null;
|
|
4766
|
+
/**
|
|
4767
|
+
* Plantillas de slots basados en atributo `row` en el light DOM.
|
|
4768
|
+
* Se inicializan una sola vez y se clonan en cada render.
|
|
4769
|
+
*/
|
|
4770
|
+
this.slotTemplates = null;
|
|
4766
4771
|
this.dependencyRenderTimeout = null;
|
|
4767
4772
|
this.stateManager = new StateManager();
|
|
4768
4773
|
this.shadow = this.attachShadow({ mode: "open" });
|
|
@@ -5207,6 +5212,16 @@ var EasyForm = class extends BrowserHTMLElement {
|
|
|
5207
5212
|
* Retorna un objeto con los valores preservados
|
|
5208
5213
|
*/
|
|
5209
5214
|
preserveCurrentValues() {
|
|
5215
|
+
let currentSchema = null;
|
|
5216
|
+
const templateName = this.template;
|
|
5217
|
+
if (templateName) {
|
|
5218
|
+
currentSchema = this.getSchemaFromTemplate(templateName);
|
|
5219
|
+
} else {
|
|
5220
|
+
currentSchema = this.schema;
|
|
5221
|
+
}
|
|
5222
|
+
if (!currentSchema) {
|
|
5223
|
+
return {};
|
|
5224
|
+
}
|
|
5210
5225
|
const form = this.shadow.querySelector("form");
|
|
5211
5226
|
const preservedValues = {};
|
|
5212
5227
|
if (!form) return preservedValues;
|
|
@@ -5214,6 +5229,8 @@ var EasyForm = class extends BrowserHTMLElement {
|
|
|
5214
5229
|
for (const input of inputs) {
|
|
5215
5230
|
const name = input.getAttribute("name");
|
|
5216
5231
|
if (!name) continue;
|
|
5232
|
+
const belongsToSchema = this.findFieldInSchema(currentSchema, name) !== null;
|
|
5233
|
+
if (!belongsToSchema) continue;
|
|
5217
5234
|
let value;
|
|
5218
5235
|
if (input instanceof HTMLInputElement) {
|
|
5219
5236
|
if (input.type === "checkbox") {
|
|
@@ -5244,16 +5261,93 @@ var EasyForm = class extends BrowserHTMLElement {
|
|
|
5244
5261
|
}
|
|
5245
5262
|
return preservedValues;
|
|
5246
5263
|
}
|
|
5264
|
+
/**
|
|
5265
|
+
* Inicializa las plantillas de slots a partir del light DOM.
|
|
5266
|
+
* Cualquier hijo directo que sea HTMLElement se considera slot; si tiene atributo `row` se usa para la posición, si no se inserta al final (-1).
|
|
5267
|
+
*/
|
|
5268
|
+
initializeSlotTemplates() {
|
|
5269
|
+
if (this.slotTemplates !== null) return;
|
|
5270
|
+
const elements = [];
|
|
5271
|
+
for (const child of Array.from(this.children)) {
|
|
5272
|
+
if (child instanceof HTMLElement) {
|
|
5273
|
+
elements.push(child);
|
|
5274
|
+
}
|
|
5275
|
+
}
|
|
5276
|
+
if (elements.length === 0) {
|
|
5277
|
+
this.slotTemplates = [];
|
|
5278
|
+
return;
|
|
5279
|
+
}
|
|
5280
|
+
this.slotTemplates = elements.map((el) => {
|
|
5281
|
+
const raw = el.hasAttribute("row") ? el.getAttribute("row") : null;
|
|
5282
|
+
const parsed = raw != null && raw !== "" ? Number(raw) : NaN;
|
|
5283
|
+
const row = Number.isFinite(parsed) ? parsed : null;
|
|
5284
|
+
return {
|
|
5285
|
+
template: el.cloneNode(true),
|
|
5286
|
+
row
|
|
5287
|
+
};
|
|
5288
|
+
});
|
|
5289
|
+
}
|
|
5290
|
+
/**
|
|
5291
|
+
* Obtiene clones de slots agrupados por índice de fila efectivo.
|
|
5292
|
+
* Cualquier valor inválido o fuera de rango se normaliza a -1 (final del formulario).
|
|
5293
|
+
*/
|
|
5294
|
+
getSlotClonesByRow(totalRows) {
|
|
5295
|
+
this.initializeSlotTemplates();
|
|
5296
|
+
const result = /* @__PURE__ */ new Map();
|
|
5297
|
+
if (!this.slotTemplates || this.slotTemplates.length === 0) {
|
|
5298
|
+
return result;
|
|
5299
|
+
}
|
|
5300
|
+
for (const { template, row } of this.slotTemplates) {
|
|
5301
|
+
let effectiveRow = typeof row === "number" ? row : -1;
|
|
5302
|
+
if (!Number.isFinite(effectiveRow)) {
|
|
5303
|
+
effectiveRow = -1;
|
|
5304
|
+
}
|
|
5305
|
+
if (effectiveRow < 0 || effectiveRow >= totalRows) {
|
|
5306
|
+
effectiveRow = -1;
|
|
5307
|
+
}
|
|
5308
|
+
const clone = template.cloneNode(true);
|
|
5309
|
+
const existing = result.get(effectiveRow) ?? [];
|
|
5310
|
+
existing.push(clone);
|
|
5311
|
+
result.set(effectiveRow, existing);
|
|
5312
|
+
}
|
|
5313
|
+
return result;
|
|
5314
|
+
}
|
|
5247
5315
|
/**
|
|
5248
5316
|
* Renderiza campos normales
|
|
5249
5317
|
*/
|
|
5250
5318
|
renderFields(container, fields) {
|
|
5251
|
-
|
|
5319
|
+
if (fields.length === 0) {
|
|
5320
|
+
const slotClones = this.getSlotClonesByRow(0);
|
|
5321
|
+
const endSlots2 = slotClones.get(-1);
|
|
5322
|
+
if (endSlots2 && endSlots2.length > 0) {
|
|
5323
|
+
for (const slotElement of endSlots2) {
|
|
5324
|
+
container.appendChild(slotElement);
|
|
5325
|
+
}
|
|
5326
|
+
}
|
|
5327
|
+
return;
|
|
5328
|
+
}
|
|
5329
|
+
const totalRows = fields.length;
|
|
5330
|
+
const slotClonesByRow = this.getSlotClonesByRow(totalRows);
|
|
5331
|
+
for (let rowIndex = 0; rowIndex < fields.length; rowIndex++) {
|
|
5332
|
+
const slotsForRow = slotClonesByRow.get(rowIndex);
|
|
5333
|
+
if (slotsForRow && slotsForRow.length > 0) {
|
|
5334
|
+
for (const slotElement of slotsForRow) {
|
|
5335
|
+
container.appendChild(slotElement);
|
|
5336
|
+
}
|
|
5337
|
+
slotClonesByRow.delete(rowIndex);
|
|
5338
|
+
}
|
|
5339
|
+
const field = fields[rowIndex];
|
|
5252
5340
|
const fieldElement = this.renderField(field);
|
|
5253
5341
|
if (fieldElement) {
|
|
5254
5342
|
container.appendChild(fieldElement);
|
|
5255
5343
|
}
|
|
5256
5344
|
}
|
|
5345
|
+
const endSlots = slotClonesByRow.get(-1);
|
|
5346
|
+
if (endSlots && endSlots.length > 0) {
|
|
5347
|
+
for (const slotElement of endSlots) {
|
|
5348
|
+
container.appendChild(slotElement);
|
|
5349
|
+
}
|
|
5350
|
+
}
|
|
5257
5351
|
}
|
|
5258
5352
|
/**
|
|
5259
5353
|
* Renderiza un campo
|
|
@@ -5511,12 +5605,7 @@ var EasyForm = class extends BrowserHTMLElement {
|
|
|
5511
5605
|
const fieldsContainer = document.createElement("div");
|
|
5512
5606
|
fieldsContainer.className = "easy-form-wizard-fields";
|
|
5513
5607
|
const currentFields = this.stateManager.getCurrentStepFields();
|
|
5514
|
-
|
|
5515
|
-
const fieldElement = this.renderField(field);
|
|
5516
|
-
if (fieldElement) {
|
|
5517
|
-
fieldsContainer.appendChild(fieldElement);
|
|
5518
|
-
}
|
|
5519
|
-
}
|
|
5608
|
+
this.renderFields(fieldsContainer, currentFields);
|
|
5520
5609
|
wizardContainer.appendChild(fieldsContainer);
|
|
5521
5610
|
const navContainer = document.createElement("div");
|
|
5522
5611
|
navContainer.className = "easy-form-wizard-nav";
|