@moni-labs/moni-ui 0.4.6 → 0.4.8
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/custom-elements.json +211 -1
- package/dist/browser/moni-ui.iife.min.js +303 -275
- package/dist/browser/moni-ui.iife.min.js.br +0 -0
- package/dist/browser/moni-ui.iife.min.js.gz +0 -0
- package/dist/browser/moni-ui.iife.min.js.map +1 -1
- package/dist/browser/moni-ui.min.js +1398 -1277
- package/dist/browser/moni-ui.min.js.br +0 -0
- package/dist/browser/moni-ui.min.js.gz +0 -0
- package/dist/browser/moni-ui.min.js.map +1 -1
- package/dist/cdn/components/moni-color-field.js +1 -0
- package/dist/cdn/components/moni-morph-modal.js +17 -4
- package/dist/cdn/components/moni-select.js +3 -3
- package/dist/cdn/components/moni-text-field.js +12 -2
- package/dist/cdn/components/moni-textarea.js +6 -2
- package/dist/cdn/importmap.json +98 -98
- package/dist/components/moni-color-field.d.ts.map +1 -1
- package/dist/components/moni-color-field.js +1 -0
- package/dist/components/moni-morph-modal.d.ts +7 -0
- package/dist/components/moni-morph-modal.d.ts.map +1 -1
- package/dist/components/moni-morph-modal.js +37 -1
- package/dist/components/moni-select.d.ts +28 -0
- package/dist/components/moni-select.d.ts.map +1 -1
- package/dist/components/moni-select.js +48 -0
- package/dist/components/moni-text-field.d.ts +45 -2
- package/dist/components/moni-text-field.d.ts.map +1 -1
- package/dist/components/moni-text-field.js +113 -1
- package/dist/components/moni-textarea.d.ts +27 -0
- package/dist/components/moni-textarea.d.ts.map +1 -1
- package/dist/components/moni-textarea.js +61 -0
- package/docs/api.json +205 -5
- package/docs/assets/moni-context-menu/placement--top.png +0 -0
- package/docs/assets/moni-select/required--false.png +0 -0
- package/docs/assets/moni-select/required--true.png +0 -0
- package/docs/assets/moni-text-field/autocomplete--default.png +0 -0
- package/docs/assets/moni-text-field/inputmode--default.png +0 -0
- package/docs/assets/moni-text-field/max--default.png +0 -0
- package/docs/assets/moni-text-field/maxlength--default.png +0 -0
- package/docs/assets/moni-text-field/min--default.png +0 -0
- package/docs/assets/moni-text-field/minlength--default.png +0 -0
- package/docs/assets/moni-text-field/pattern--default.png +0 -0
- package/docs/assets/moni-text-field/readonly--false.png +0 -0
- package/docs/assets/moni-text-field/readonly--true.png +0 -0
- package/docs/assets/moni-text-field/required--false.png +0 -0
- package/docs/assets/moni-text-field/required--true.png +0 -0
- package/docs/assets/moni-text-field/step--default.png +0 -0
- package/docs/assets/moni-text-field/type--color.png +0 -0
- package/docs/assets/moni-text-field/type--date.png +0 -0
- package/docs/assets/moni-text-field/type--datetime-local.png +0 -0
- package/docs/assets/moni-text-field/type--month.png +0 -0
- package/docs/assets/moni-text-field/type--time.png +0 -0
- package/docs/assets/moni-text-field/type--week.png +0 -0
- package/docs/assets/moni-textarea/autocomplete--default.png +0 -0
- package/docs/assets/moni-textarea/minlength--default.png +0 -0
- package/docs/assets/moni-textarea/readonly--false.png +0 -0
- package/docs/assets/moni-textarea/readonly--true.png +0 -0
- package/docs/assets/moni-textarea/required--false.png +0 -0
- package/docs/assets/moni-textarea/required--true.png +0 -0
- package/docs/components/morph-modal.md +3 -0
- package/docs/components/select.md +15 -1
- package/docs/components/text-field.md +89 -1
- package/docs/components/textarea.md +34 -1
- package/package.json +90 -90
- package/src/components/moni-color-field.ts +1 -0
- package/src/components/moni-morph-modal.test.ts +26 -0
- package/src/components/moni-morph-modal.ts +33 -1
- package/src/components/moni-select.test.ts +34 -0
- package/src/components/moni-select.ts +54 -0
- package/src/components/moni-text-field.test.ts +78 -0
- package/src/components/moni-text-field.ts +109 -2
- package/src/components/moni-textarea.ts +62 -0
|
@@ -158,6 +158,15 @@ export class MoniSelect extends MoniElement {
|
|
|
158
158
|
*/
|
|
159
159
|
@property({ type: Boolean, reflect: true }) disabled = false;
|
|
160
160
|
|
|
161
|
+
/**
|
|
162
|
+
* Obliga a elegir una opción antes de enviar el formulario.
|
|
163
|
+
*
|
|
164
|
+
* El `<input>` visible es de sólo lectura, así que la validación nativa no
|
|
165
|
+
* se aplica sobre él: la restricción se declara en el host con
|
|
166
|
+
* `ElementInternals.setValidity`, que es lo que mira el formulario.
|
|
167
|
+
*/
|
|
168
|
+
@property({ type: Boolean, reflect: true }) required = false;
|
|
169
|
+
|
|
161
170
|
/**
|
|
162
171
|
* Si es verdadero, muestra un indicador de carga (progreso lineal).
|
|
163
172
|
* @type {boolean}
|
|
@@ -281,6 +290,50 @@ export class MoniSelect extends MoniElement {
|
|
|
281
290
|
|
|
282
291
|
@query('slot') private _slot!: HTMLSlotElement;
|
|
283
292
|
@query('input') private _input!: HTMLInputElement;
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Declara la validez del host según `required`.
|
|
296
|
+
*
|
|
297
|
+
* No se puede delegar en el `<input>` interno porque es `readonly`, y un
|
|
298
|
+
* campo de sólo lectura queda excluido de la validación de restricciones. El
|
|
299
|
+
* ancla sigue siendo ese input para que el navegador tenga dónde mostrar el
|
|
300
|
+
* mensaje y a dónde llevar el foco.
|
|
301
|
+
*/
|
|
302
|
+
/**
|
|
303
|
+
* API de validación equivalente a la de un control nativo.
|
|
304
|
+
*
|
|
305
|
+
* Los elementos form-associated participan en la validación del formulario,
|
|
306
|
+
* pero no reciben estos miembros automáticamente: hay que exponerlos para que
|
|
307
|
+
* un `moni-select` se pueda interrogar igual que un `<input>`.
|
|
308
|
+
*/
|
|
309
|
+
get validity(): ValidityState {
|
|
310
|
+
return this._internals.validity;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
get validationMessage(): string {
|
|
314
|
+
return this._internals.validationMessage;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
checkValidity(): boolean {
|
|
318
|
+
return this._internals.checkValidity();
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
reportValidity(): boolean {
|
|
322
|
+
return this._internals.reportValidity();
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
private _syncValidity() {
|
|
326
|
+
if (!this._internals?.setValidity) return;
|
|
327
|
+
if (this.required && !this.value) {
|
|
328
|
+
this._internals.setValidity(
|
|
329
|
+
{ valueMissing: true },
|
|
330
|
+
'Selecciona una opción.',
|
|
331
|
+
this._input ?? undefined
|
|
332
|
+
);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
this._internals.setValidity({});
|
|
336
|
+
}
|
|
284
337
|
@query('.dropdown-menu') private _menu?: HTMLElement;
|
|
285
338
|
|
|
286
339
|
static override styles = [
|
|
@@ -664,6 +717,7 @@ export class MoniSelect extends MoniElement {
|
|
|
664
717
|
if (changedProperties.has('value')) {
|
|
665
718
|
this._internals?.setFormValue?.(this.value);
|
|
666
719
|
}
|
|
720
|
+
this._syncValidity();
|
|
667
721
|
if (
|
|
668
722
|
changedProperties.has('_open') ||
|
|
669
723
|
changedProperties.has('_drilldownPath') ||
|
|
@@ -254,3 +254,81 @@ describe('moni-text-field · nombre accesible', () => {
|
|
|
254
254
|
el.remove();
|
|
255
255
|
});
|
|
256
256
|
})
|
|
257
|
+
|
|
258
|
+
describe('moni-text-field · restricciones nativas', () => {
|
|
259
|
+
/*
|
|
260
|
+
* El componente sólo reenviaba type/placeholder/disabled/value/name, así que
|
|
261
|
+
* cualquier campo con `required` o `autocomplete` tenía que renunciar a
|
|
262
|
+
* moni-ui y usar un input nativo.
|
|
263
|
+
*/
|
|
264
|
+
it('reenvía las restricciones al input interno', async () => {
|
|
265
|
+
const el = document.createElement('moni-text-field') as HTMLElement & {
|
|
266
|
+
updateComplete: Promise<unknown>;
|
|
267
|
+
[key: string]: unknown;
|
|
268
|
+
};
|
|
269
|
+
Object.assign(el, {
|
|
270
|
+
label: 'Correo',
|
|
271
|
+
type: 'email',
|
|
272
|
+
required: true,
|
|
273
|
+
autocomplete: 'email',
|
|
274
|
+
maxlength: 40,
|
|
275
|
+
minlength: 5,
|
|
276
|
+
pattern: '.+@.+',
|
|
277
|
+
inputmode: 'email'
|
|
278
|
+
});
|
|
279
|
+
document.body.appendChild(el);
|
|
280
|
+
await el.updateComplete;
|
|
281
|
+
|
|
282
|
+
const input = el.shadowRoot?.querySelector('input') as HTMLInputElement;
|
|
283
|
+
expect(input.required).toBe(true);
|
|
284
|
+
expect(input.getAttribute('autocomplete')).toBe('email');
|
|
285
|
+
expect(input.maxLength).toBe(40);
|
|
286
|
+
expect(input.minLength).toBe(5);
|
|
287
|
+
expect(input.getAttribute('pattern')).toBe('.+@.+');
|
|
288
|
+
expect(input.getAttribute('inputmode')).toBe('email');
|
|
289
|
+
el.remove();
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it('acepta los tipos de fecha y hora', async () => {
|
|
293
|
+
const el = document.createElement('moni-text-field') as HTMLElement & {
|
|
294
|
+
type: string;
|
|
295
|
+
updateComplete: Promise<unknown>;
|
|
296
|
+
};
|
|
297
|
+
el.type = 'date';
|
|
298
|
+
document.body.appendChild(el);
|
|
299
|
+
await el.updateComplete;
|
|
300
|
+
expect(el.shadowRoot?.querySelector('input')?.getAttribute('type')).toBe('date');
|
|
301
|
+
el.remove();
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it('publica la validez en el host para que el formulario la vea', async () => {
|
|
305
|
+
// jsdom no implementa checkValidity() en custom elements form-associated,
|
|
306
|
+
// así que se observa la llamada a setValidity. El bloqueo real del envío
|
|
307
|
+
// se verifica en navegador.
|
|
308
|
+
const calls: Array<Record<string, unknown>> = [];
|
|
309
|
+
const originalAttach = HTMLElement.prototype.attachInternals;
|
|
310
|
+
HTMLElement.prototype.attachInternals = function spy(this: HTMLElement) {
|
|
311
|
+
const internals = originalAttach.call(this);
|
|
312
|
+
const setValidity = internals.setValidity.bind(internals);
|
|
313
|
+
internals.setValidity = ((flags, message, anchor) => {
|
|
314
|
+
// ValidityState expone sus flags como getters del prototipo, así que un
|
|
315
|
+
// spread devolvería {}: hay que leerlas uña a uña.
|
|
316
|
+
calls.push({ valueMissing: flags?.valueMissing === true });
|
|
317
|
+
return setValidity(flags, message, anchor);
|
|
318
|
+
}) as typeof internals.setValidity;
|
|
319
|
+
return internals;
|
|
320
|
+
};
|
|
321
|
+
const el = document.createElement('moni-text-field') as HTMLElement & {
|
|
322
|
+
required: boolean;
|
|
323
|
+
updateComplete: Promise<unknown>;
|
|
324
|
+
};
|
|
325
|
+
HTMLElement.prototype.attachInternals = originalAttach;
|
|
326
|
+
|
|
327
|
+
el.required = true;
|
|
328
|
+
document.body.appendChild(el);
|
|
329
|
+
await el.updateComplete;
|
|
330
|
+
|
|
331
|
+
expect(calls.some((c) => c.valueMissing === true)).toBe(true);
|
|
332
|
+
el.remove();
|
|
333
|
+
});
|
|
334
|
+
})
|
|
@@ -114,7 +114,7 @@ export class MoniTextField extends MoniElement {
|
|
|
114
114
|
|
|
115
115
|
/**
|
|
116
116
|
* El tipo de input HTML nativo.
|
|
117
|
-
* @type {'text' | 'password' | 'email' | 'number' | 'tel' | 'url' | 'search'}
|
|
117
|
+
* @type {'text' | 'password' | 'email' | 'number' | 'tel' | 'url' | 'search' | 'date' | 'time' | 'datetime-local' | 'month' | 'week' | 'color'}
|
|
118
118
|
* @default 'text'
|
|
119
119
|
*/
|
|
120
120
|
@property({ reflect: true })
|
|
@@ -125,7 +125,13 @@ export class MoniTextField extends MoniElement {
|
|
|
125
125
|
| 'number'
|
|
126
126
|
| 'tel'
|
|
127
127
|
| 'url'
|
|
128
|
-
| 'search'
|
|
128
|
+
| 'search'
|
|
129
|
+
| 'date'
|
|
130
|
+
| 'time'
|
|
131
|
+
| 'datetime-local'
|
|
132
|
+
| 'month'
|
|
133
|
+
| 'week'
|
|
134
|
+
| 'color' = 'text';
|
|
129
135
|
|
|
130
136
|
/**
|
|
131
137
|
* Nombre del icono inicial (leading) (Material Symbols).
|
|
@@ -202,6 +208,50 @@ export class MoniTextField extends MoniElement {
|
|
|
202
208
|
*/
|
|
203
209
|
@property({ reflect: true }) placeholder = '';
|
|
204
210
|
|
|
211
|
+
/*
|
|
212
|
+
* Restricciones nativas.
|
|
213
|
+
*
|
|
214
|
+
* Antes ninguna de estas llegaba al `<input>` interno: el componente sólo
|
|
215
|
+
* reenviaba `type`, `placeholder`, `disabled`, `value` y `name`. Eso dejaba
|
|
216
|
+
* fuera el autocompletado de contraseñas, el teclado correcto en móvil, el
|
|
217
|
+
* límite de caracteres y toda la validación de restricciones, así que cada
|
|
218
|
+
* consumidor que necesitaba una de ellas tenía que renunciar al componente y
|
|
219
|
+
* usar un input nativo.
|
|
220
|
+
*
|
|
221
|
+
* Se reflejan al host además de reenviarse para que `[required]` y compañía
|
|
222
|
+
* puedan usarse como selectores CSS desde fuera.
|
|
223
|
+
*/
|
|
224
|
+
|
|
225
|
+
/** Marca el campo como obligatorio y lo integra en la validación del formulario. */
|
|
226
|
+
@property({ type: Boolean, reflect: true }) required = false;
|
|
227
|
+
|
|
228
|
+
/** Impide editar el valor sin sacarlo del envío ni atenuarlo como `disabled`. */
|
|
229
|
+
@property({ type: Boolean, reflect: true }) readonly = false;
|
|
230
|
+
|
|
231
|
+
/** Pista de autocompletado del navegador, por ejemplo `email` o `current-password`. */
|
|
232
|
+
@property({ reflect: true }) autocomplete = '';
|
|
233
|
+
|
|
234
|
+
/** Teclado virtual a mostrar en móvil, por ejemplo `numeric` o `tel`. */
|
|
235
|
+
@property({ reflect: true }) inputmode = '';
|
|
236
|
+
|
|
237
|
+
/** Máximo de caracteres aceptados. */
|
|
238
|
+
@property({ type: Number, reflect: true }) maxlength: number | null = null;
|
|
239
|
+
|
|
240
|
+
/** Mínimo de caracteres aceptados. */
|
|
241
|
+
@property({ type: Number, reflect: true }) minlength: number | null = null;
|
|
242
|
+
|
|
243
|
+
/** Valor mínimo para `number` y los tipos de fecha y hora. */
|
|
244
|
+
@property({ reflect: true }) min = '';
|
|
245
|
+
|
|
246
|
+
/** Valor máximo para `number` y los tipos de fecha y hora. */
|
|
247
|
+
@property({ reflect: true }) max = '';
|
|
248
|
+
|
|
249
|
+
/** Incremento para `number` y los tipos de fecha y hora. */
|
|
250
|
+
@property({ reflect: true }) step = '';
|
|
251
|
+
|
|
252
|
+
/** Expresión regular que debe cumplir el valor. */
|
|
253
|
+
@property({ reflect: true }) pattern = '';
|
|
254
|
+
|
|
205
255
|
/**
|
|
206
256
|
* Patrón Inputmask. Admite opcionales `[]`, grupos `()`, alternadores `|`,
|
|
207
257
|
* cuantificadores `{n,m}` y los tokens `9`, `a`, `*` y `K` (RUT).
|
|
@@ -334,11 +384,58 @@ export class MoniTextField extends MoniElement {
|
|
|
334
384
|
}
|
|
335
385
|
if (changed.has('disabled')) this._input.disabled = this.disabled;
|
|
336
386
|
}
|
|
387
|
+
this._syncValidity();
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Copia la validez del `<input>` interno al host.
|
|
392
|
+
*
|
|
393
|
+
* Reenviar `required` o `pattern` no basta: el navegador valida el
|
|
394
|
+
* formulario mirando los controles asociados a él, y el que aquí participa
|
|
395
|
+
* es el host, no el input del Shadow DOM. Sin este puente el campo se
|
|
396
|
+
* pintaría como obligatorio pero el envío no se detendría.
|
|
397
|
+
*
|
|
398
|
+
* El tercer argumento ancla el globo de validación al input real, para que
|
|
399
|
+
* el navegador tenga dónde mostrarlo y a dónde mover el foco.
|
|
400
|
+
*/
|
|
401
|
+
/**
|
|
402
|
+
* API de validación equivalente a la de un control nativo.
|
|
403
|
+
*
|
|
404
|
+
* Los elementos form-associated participan en la validación del formulario,
|
|
405
|
+
* pero no reciben estos miembros automáticamente: hay que exponerlos para que
|
|
406
|
+
* un `moni-text-field` se pueda interrogar igual que un `<input>`.
|
|
407
|
+
*/
|
|
408
|
+
get validity(): ValidityState {
|
|
409
|
+
return this._internals.validity;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
get validationMessage(): string {
|
|
413
|
+
return this._internals.validationMessage;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
checkValidity(): boolean {
|
|
417
|
+
return this._internals.checkValidity();
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
reportValidity(): boolean {
|
|
421
|
+
return this._internals.reportValidity();
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
private _syncValidity() {
|
|
425
|
+
if (!this._input || !this._internals?.setValidity) return;
|
|
426
|
+
this._internals.setValidity(
|
|
427
|
+
this._input.validity,
|
|
428
|
+
this._input.validationMessage,
|
|
429
|
+
this._input
|
|
430
|
+
);
|
|
337
431
|
}
|
|
338
432
|
|
|
339
433
|
private _handleInput(e: Event) {
|
|
340
434
|
const target = e.target as HTMLInputElement;
|
|
341
435
|
this.value = target.value;
|
|
436
|
+
// Al teclear, `value` no siempre cambia de referencia (máscaras), así que
|
|
437
|
+
// la validez se refresca aquí y no sólo desde `updated()`.
|
|
438
|
+
this._syncValidity();
|
|
342
439
|
emitMoniEvent(this, 'moni-input', {
|
|
343
440
|
detail: { value: this.value, unmaskedValue: this.unmaskedValue, originalEvent: e }
|
|
344
441
|
});
|
|
@@ -499,6 +596,16 @@ export class MoniTextField extends MoniElement {
|
|
|
499
596
|
type=${this.type}
|
|
500
597
|
placeholder=${placeholder}
|
|
501
598
|
?disabled=${this.disabled}
|
|
599
|
+
?required=${this.required}
|
|
600
|
+
?readonly=${this.readonly}
|
|
601
|
+
autocomplete=${ifDefined(this.autocomplete || undefined)}
|
|
602
|
+
inputmode=${ifDefined(this.inputmode || undefined)}
|
|
603
|
+
maxlength=${ifDefined(this.maxlength ?? undefined)}
|
|
604
|
+
minlength=${ifDefined(this.minlength ?? undefined)}
|
|
605
|
+
min=${ifDefined(this.min || undefined)}
|
|
606
|
+
max=${ifDefined(this.max || undefined)}
|
|
607
|
+
step=${ifDefined(this.step || undefined)}
|
|
608
|
+
pattern=${ifDefined(this.pattern || undefined)}
|
|
502
609
|
.value=${this.value}
|
|
503
610
|
name=${ifDefined(this.name || undefined)}
|
|
504
611
|
class=${isActive ? 'active' : ''}
|
|
@@ -148,6 +148,24 @@ export class MoniTextarea extends MoniElement {
|
|
|
148
148
|
*/
|
|
149
149
|
@property({ type: Number, reflect: true }) maxlength: number | null = null;
|
|
150
150
|
|
|
151
|
+
/*
|
|
152
|
+
* Restricciones nativas. Antes sólo `maxlength` llegaba al `<textarea>`
|
|
153
|
+
* interno, así que un campo obligatorio o de sólo lectura obligaba a
|
|
154
|
+
* abandonar el componente y usar un control nativo.
|
|
155
|
+
*/
|
|
156
|
+
|
|
157
|
+
/** Marca el campo como obligatorio y lo integra en la validación del formulario. */
|
|
158
|
+
@property({ type: Boolean, reflect: true }) required = false;
|
|
159
|
+
|
|
160
|
+
/** Impide editar el valor sin sacarlo del envío ni atenuarlo como `disabled`. */
|
|
161
|
+
@property({ type: Boolean, reflect: true }) readonly = false;
|
|
162
|
+
|
|
163
|
+
/** Mínimo de caracteres aceptados. */
|
|
164
|
+
@property({ type: Number, reflect: true }) minlength: number | null = null;
|
|
165
|
+
|
|
166
|
+
/** Pista de autocompletado del navegador. */
|
|
167
|
+
@property({ reflect: true }) autocomplete = '';
|
|
168
|
+
|
|
151
169
|
/**
|
|
152
170
|
* Oculta la visualización del contador de caracteres cuando se establece `maxlength`.
|
|
153
171
|
* @type {boolean}
|
|
@@ -266,6 +284,46 @@ export class MoniTextarea extends MoniElement {
|
|
|
266
284
|
changed.has('maxRows')
|
|
267
285
|
) this._resizeTextarea();
|
|
268
286
|
}
|
|
287
|
+
this._syncValidity();
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Copia la validez del `<textarea>` interno al host.
|
|
292
|
+
*
|
|
293
|
+
* El navegador valida mirando los controles asociados al formulario, y el
|
|
294
|
+
* que participa es el host, no el control del Shadow DOM: sin este puente
|
|
295
|
+
* `required` se pintaría pero no detendría el envío.
|
|
296
|
+
*/
|
|
297
|
+
/**
|
|
298
|
+
* API de validación equivalente a la de un control nativo.
|
|
299
|
+
*
|
|
300
|
+
* Los elementos form-associated participan en la validación del formulario,
|
|
301
|
+
* pero no reciben estos miembros automáticamente: hay que exponerlos para que
|
|
302
|
+
* un `moni-textarea` se pueda interrogar igual que un `<input>`.
|
|
303
|
+
*/
|
|
304
|
+
get validity(): ValidityState {
|
|
305
|
+
return this._internals.validity;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
get validationMessage(): string {
|
|
309
|
+
return this._internals.validationMessage;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
checkValidity(): boolean {
|
|
313
|
+
return this._internals.checkValidity();
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
reportValidity(): boolean {
|
|
317
|
+
return this._internals.reportValidity();
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
private _syncValidity() {
|
|
321
|
+
if (!this._input || !this._internals?.setValidity) return;
|
|
322
|
+
this._internals.setValidity(
|
|
323
|
+
this._input.validity,
|
|
324
|
+
this._input.validationMessage,
|
|
325
|
+
this._input
|
|
326
|
+
);
|
|
269
327
|
}
|
|
270
328
|
|
|
271
329
|
static override styles = [sharedStyles, fieldStyles, css`
|
|
@@ -361,8 +419,12 @@ export class MoniTextarea extends MoniElement {
|
|
|
361
419
|
part="input"
|
|
362
420
|
rows=${this.rows}
|
|
363
421
|
maxlength=${ifDefined(this.maxlength ?? undefined)}
|
|
422
|
+
minlength=${ifDefined(this.minlength ?? undefined)}
|
|
364
423
|
placeholder=${placeholder}
|
|
365
424
|
?disabled=${this.disabled}
|
|
425
|
+
?required=${this.required}
|
|
426
|
+
?readonly=${this.readonly}
|
|
427
|
+
autocomplete=${ifDefined(this.autocomplete || undefined)}
|
|
366
428
|
.value=${this.value}
|
|
367
429
|
name=${ifDefined(this.name || undefined)}
|
|
368
430
|
class=${isActive ? 'active' : ''}
|