mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-12 20:19:13 +00:00
more work on form association
This commit is contained in:
@@ -5,7 +5,39 @@ layout: ../../../layouts/ComponentLayout.astro
|
||||
---
|
||||
|
||||
```html:preview
|
||||
<wa-textarea></wa-textarea>
|
||||
<form id="form-textarea">
|
||||
<wa-textarea required></wa-textarea>
|
||||
|
||||
<button type="reset">Reset</button>
|
||||
<button>Submit</submit>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
document.querySelector("#form-textarea wa-textarea").addEventListener("invalid", () => {
|
||||
console.log("invalid")
|
||||
})
|
||||
|
||||
document.querySelector("#form-textarea wa-textarea").addEventListener("wa-invalid", () => {
|
||||
console.log("wa-invalid")
|
||||
})
|
||||
|
||||
const control = document.querySelector("wa-textarea")
|
||||
|
||||
setTimeout(async () => {
|
||||
control.setCustomValidity('error');
|
||||
control.disabled = false;
|
||||
await control.updateComplete;
|
||||
const emittedEvents = [];
|
||||
|
||||
control.addEventListener('wa-invalid', e => emittedEvents.push(e));
|
||||
|
||||
control.reportValidity();
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 1))
|
||||
|
||||
console.log(emittedEvents)
|
||||
}, 1000)
|
||||
</script>
|
||||
```
|
||||
|
||||
```jsx:react
|
||||
@@ -156,4 +188,4 @@ Textareas will automatically resize to expand to fit their content when `resize`
|
||||
import WaTextarea from '@shoelace-style/shoelace/dist/react/textarea';
|
||||
|
||||
const App = () => <WaTextarea resize="auto" />;
|
||||
```
|
||||
```
|
||||
@@ -1,18 +1,17 @@
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import { defaultValue } from '../../internal/default-value.js';
|
||||
import { FormControlController } from '../../internal/form.js';
|
||||
import { HasSlotController } from '../../internal/slot.js';
|
||||
import { html } from 'lit';
|
||||
import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { live } from 'lit/directives/live.js';
|
||||
import { MirrorValidator } from '../../internal/validators/mirror-validator.js';
|
||||
import { property, query, state } from 'lit/decorators.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import { WebAwesomeFormAssociated } from '../../internal/webawesome-element.js';
|
||||
import componentStyles from '../../styles/component.styles.js';
|
||||
import formControlStyles from '../../styles/form-control.styles.js';
|
||||
import styles from './textarea.styles.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import type { CSSResultGroup } from 'lit';
|
||||
import type { WebAwesomeFormControl } from '../../internal/webawesome-element.js';
|
||||
|
||||
/**
|
||||
* @summary Textareas collect data from the user and allow multiple lines of text.
|
||||
@@ -43,16 +42,19 @@ import type { WebAwesomeFormControl } from '../../internal/webawesome-element.js
|
||||
* @cssproperty --border-width - The width of the textarea's borders.
|
||||
* @cssproperty --box-shadow - The shadow effects around the edges of the textarea.
|
||||
*/
|
||||
export default class WaTextarea extends WebAwesomeElement implements WebAwesomeFormControl {
|
||||
export default class WaTextarea extends WebAwesomeFormAssociated {
|
||||
static formAssociated = true;
|
||||
static styles: CSSResultGroup = [componentStyles, formControlStyles, styles];
|
||||
static get validators() {
|
||||
return [MirrorValidator];
|
||||
}
|
||||
|
||||
private readonly formControlController = new FormControlController(this, {
|
||||
assumeInteractionOn: ['wa-blur', 'wa-input']
|
||||
});
|
||||
assumeInteractionOn = ['wa-blur', 'wa-input'];
|
||||
private readonly hasSlotController = new HasSlotController(this, 'help-text', 'label');
|
||||
private resizeObserver: ResizeObserver;
|
||||
|
||||
@query('.textarea__control') input: HTMLTextAreaElement;
|
||||
@query('.textarea__control') formControl: HTMLTextAreaElement;
|
||||
|
||||
@state() private hasFocus = false;
|
||||
@property() title = ''; // make reactive to pass through
|
||||
@@ -95,7 +97,7 @@ export default class WaTextarea extends WebAwesomeElement implements WebAwesomeF
|
||||
* to place the form control outside of a form and associate it with the form that has this `id`. The form must be in
|
||||
* the same document or shadow root for this to work.
|
||||
*/
|
||||
@property({ reflect: true }) form = '';
|
||||
@property({ reflect: true }) form = null;
|
||||
|
||||
/** Makes the textarea a required field. */
|
||||
@property({ type: Boolean, reflect: true }) required = false;
|
||||
@@ -144,16 +146,6 @@ export default class WaTextarea extends WebAwesomeElement implements WebAwesomeF
|
||||
/** The default value of the form control. Primarily used for resetting the form control. */
|
||||
@defaultValue() defaultValue = '';
|
||||
|
||||
/** Gets the validity state object */
|
||||
get validity() {
|
||||
return this.input.validity;
|
||||
}
|
||||
|
||||
/** Gets the validation message */
|
||||
get validationMessage() {
|
||||
return this.input.validationMessage;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.resizeObserver = new ResizeObserver(() => this.setTextareaHeight());
|
||||
@@ -165,7 +157,7 @@ export default class WaTextarea extends WebAwesomeElement implements WebAwesomeF
|
||||
}
|
||||
|
||||
firstUpdated() {
|
||||
this.formControlController.updateValidity();
|
||||
this.checkValidity();
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
@@ -176,27 +168,26 @@ export default class WaTextarea extends WebAwesomeElement implements WebAwesomeF
|
||||
private handleBlur() {
|
||||
this.hasFocus = false;
|
||||
this.emit('wa-blur');
|
||||
this.checkValidity();
|
||||
}
|
||||
|
||||
private handleChange() {
|
||||
this.value = this.input.value;
|
||||
this.setTextareaHeight();
|
||||
this.emit('wa-change');
|
||||
this.checkValidity();
|
||||
}
|
||||
|
||||
private handleFocus() {
|
||||
this.hasFocus = true;
|
||||
this.emit('wa-focus');
|
||||
this.checkValidity();
|
||||
}
|
||||
|
||||
private handleInput() {
|
||||
this.value = this.input.value;
|
||||
this.emit('wa-input');
|
||||
}
|
||||
|
||||
private handleInvalid(event: Event) {
|
||||
this.formControlController.setValidity(false);
|
||||
this.formControlController.emitInvalidEvent(event);
|
||||
this.checkValidity();
|
||||
}
|
||||
|
||||
private setTextareaHeight() {
|
||||
@@ -208,12 +199,6 @@ export default class WaTextarea extends WebAwesomeElement implements WebAwesomeF
|
||||
}
|
||||
}
|
||||
|
||||
@watch('disabled', { waitUntilFirstUpdate: true })
|
||||
handleDisabledChange() {
|
||||
// Disabled form controls are always valid
|
||||
this.formControlController.setValidity(this.disabled);
|
||||
}
|
||||
|
||||
@watch('rows', { waitUntilFirstUpdate: true })
|
||||
handleRowsChange() {
|
||||
this.setTextareaHeight();
|
||||
@@ -222,7 +207,7 @@ export default class WaTextarea extends WebAwesomeElement implements WebAwesomeF
|
||||
@watch('value', { waitUntilFirstUpdate: true })
|
||||
async handleValueChange() {
|
||||
await this.updateComplete;
|
||||
this.formControlController.updateValidity();
|
||||
this.checkValidity();
|
||||
this.setTextareaHeight();
|
||||
}
|
||||
|
||||
@@ -234,6 +219,7 @@ export default class WaTextarea extends WebAwesomeElement implements WebAwesomeF
|
||||
/** Removes focus from the textarea. */
|
||||
blur() {
|
||||
this.input.blur();
|
||||
// this.checkValidity();
|
||||
}
|
||||
|
||||
/** Selects all the text in the textarea. */
|
||||
@@ -282,27 +268,6 @@ export default class WaTextarea extends WebAwesomeElement implements WebAwesomeF
|
||||
}
|
||||
}
|
||||
|
||||
/** Checks for validity but does not show a validation message. Returns `true` when valid and `false` when invalid. */
|
||||
checkValidity() {
|
||||
return this.input.checkValidity();
|
||||
}
|
||||
|
||||
/** Gets the associated form, if one exists. */
|
||||
getForm(): HTMLFormElement | null {
|
||||
return this.formControlController.getForm();
|
||||
}
|
||||
|
||||
/** Checks for validity and shows the browser's validation message if the control is invalid. */
|
||||
reportValidity() {
|
||||
return this.input.reportValidity();
|
||||
}
|
||||
|
||||
/** Sets a custom validation message. Pass an empty string to restore validity. */
|
||||
setCustomValidity(message: string) {
|
||||
this.input.setCustomValidity(message);
|
||||
this.formControlController.updateValidity();
|
||||
}
|
||||
|
||||
render() {
|
||||
const hasLabelSlot = this.hasSlotController.test('label');
|
||||
const hasHelpTextSlot = this.hasSlotController.test('help-text');
|
||||
@@ -371,7 +336,6 @@ export default class WaTextarea extends WebAwesomeElement implements WebAwesomeF
|
||||
aria-describedby="help-text"
|
||||
@change=${this.handleChange}
|
||||
@input=${this.handleInput}
|
||||
@invalid=${this.handleInvalid}
|
||||
@focus=${this.handleFocus}
|
||||
@blur=${this.handleBlur}
|
||||
></textarea>
|
||||
|
||||
@@ -205,7 +205,7 @@ describe('<wa-textarea>', () => {
|
||||
});
|
||||
|
||||
it('should be invalid when setCustomValidity() is called with a non-empty value', async () => {
|
||||
const textarea = await fixture<HTMLFormElement>(html` <wa-textarea></wa-textarea> `);
|
||||
const textarea = await fixture<HTMLFormElement>(html`<wa-textarea></wa-textarea>`);
|
||||
|
||||
textarea.setCustomValidity('Invalid selection');
|
||||
await textarea.updateComplete;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { expect, fixture } from '@open-wc/testing';
|
||||
import { aTimeout, expect, fixture } from '@open-wc/testing';
|
||||
import type { WebAwesomeFormControl } from '../webawesome-element.js';
|
||||
|
||||
type CreateControlFn = () => Promise<WebAwesomeFormControl>;
|
||||
@@ -274,7 +274,11 @@ function runSpecialTests_standard(createControl: CreateControlFn) {
|
||||
control.disabled = false;
|
||||
await control.updateComplete;
|
||||
const emittedEvents = checkEventEmissions(control, 'wa-invalid', () => control.reportValidity());
|
||||
expect(emittedEvents.length).to.equal(1);
|
||||
|
||||
control.reportValidity();
|
||||
|
||||
// 2 is the expected amount. Calling `reportValidity()` will focus the textarea causing a second invalid event to fire.
|
||||
expect(emittedEvents.length).to.equal(2);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
43
src/internal/validators/mirror-validator.ts
Normal file
43
src/internal/validators/mirror-validator.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import type { Validator } from '../webawesome-element.js';
|
||||
|
||||
type ValidatorElement = HTMLElement & {
|
||||
value: string | null | File | FormData;
|
||||
formControl?: HTMLElement & ElementInternals;
|
||||
};
|
||||
|
||||
/**
|
||||
* This validator is for if you have an exact copy of your element in the shadow DOM. Rather than needing
|
||||
* custom translations and error messages, you can simply rely on the element "formControl" in your shadow dom.
|
||||
*/
|
||||
export const MirrorValidator: Validator<ValidatorElement> = {
|
||||
checkValidity(element) {
|
||||
const formControl = element.formControl;
|
||||
|
||||
const validity: ReturnType<Validator<ValidatorElement>['checkValidity']> = {
|
||||
message: '',
|
||||
isValid: true,
|
||||
invalidKeys: []
|
||||
};
|
||||
|
||||
if (!formControl) return validity;
|
||||
|
||||
const isValid = formControl.checkValidity();
|
||||
if (isValid) return validity;
|
||||
|
||||
validity.isValid = false;
|
||||
validity.message = formControl.validationMessage;
|
||||
for (const key in formControl.validity) {
|
||||
if (key === 'valid') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const checkedKey = key as Exclude<keyof ValidityState, 'valid'>;
|
||||
|
||||
if (formControl.validity[checkedKey]) {
|
||||
validity.invalidKeys.push(checkedKey);
|
||||
}
|
||||
}
|
||||
|
||||
return validity;
|
||||
}
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { LitElement, type PropertyValueMap } from 'lit';
|
||||
import { LitElement, type PropertyValues } from 'lit';
|
||||
import { property } from 'lit/decorators.js';
|
||||
|
||||
// Match event type name strings that are registered on GlobalEventHandlersEventMap...
|
||||
@@ -140,12 +140,12 @@ export default class WebAwesomeElement extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
interface Validator<
|
||||
export interface Validator<
|
||||
T extends HTMLElement & { value: string | null | File | FormData } = HTMLElement & {
|
||||
value: string | null | File | FormData;
|
||||
}
|
||||
> {
|
||||
observedAttributes: string[];
|
||||
observedAttributes?: string[];
|
||||
checkValidity: (element: T) => {
|
||||
message: string;
|
||||
isValid: boolean;
|
||||
@@ -153,8 +153,40 @@ interface Validator<
|
||||
};
|
||||
}
|
||||
|
||||
export interface WebAwesomeFormControl extends WebAwesomeElement {
|
||||
// Form attributes
|
||||
name: string;
|
||||
value: unknown;
|
||||
disabled?: boolean;
|
||||
defaultValue?: unknown;
|
||||
defaultChecked?: boolean;
|
||||
form?: string;
|
||||
|
||||
// Constraint validation attributes
|
||||
pattern?: string;
|
||||
min?: number | string | Date;
|
||||
max?: number | string | Date;
|
||||
step?: number | 'any';
|
||||
required?: boolean;
|
||||
minlength?: number;
|
||||
maxlength?: number;
|
||||
|
||||
// Form validation properties
|
||||
readonly validity: ValidityState;
|
||||
readonly validationMessage: string;
|
||||
|
||||
// Form validation methods
|
||||
checkValidity: () => boolean;
|
||||
getForm: () => HTMLFormElement | null;
|
||||
reportValidity: () => boolean;
|
||||
setCustomValidity: (message: string) => void;
|
||||
}
|
||||
|
||||
// setFormValue omitted so that we can use `setValue`
|
||||
export class WebAwesomeFormControl extends WebAwesomeElement implements Omit<ElementInternals, 'setFormValue'> {
|
||||
export class WebAwesomeFormAssociated
|
||||
extends WebAwesomeElement
|
||||
implements Omit<ElementInternals, 'form' | 'setFormValue'>, WebAwesomeFormControl
|
||||
{
|
||||
static formAssociated = true;
|
||||
|
||||
static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true };
|
||||
@@ -188,24 +220,17 @@ export class WebAwesomeFormControl extends WebAwesomeElement implements Omit<Ele
|
||||
|
||||
// Form attributes
|
||||
// These should properly just use `@property` accessors.
|
||||
name: string;
|
||||
value: string | FormData | null | File;
|
||||
disabled?: boolean;
|
||||
defaultValue: string | FormData | null | File;
|
||||
defaultChecked?: boolean;
|
||||
|
||||
// Constraint validation attributes
|
||||
pattern?: string;
|
||||
min?: number | string | Date;
|
||||
max?: number | string | Date;
|
||||
step?: number | 'any';
|
||||
required?: boolean;
|
||||
minlength?: number;
|
||||
maxlength?: number;
|
||||
name: string = '';
|
||||
value: string | FormData | null | File = null;
|
||||
defaultValue: string | FormData | null | File = null;
|
||||
disabled: boolean = false;
|
||||
required: boolean = false;
|
||||
|
||||
// Form validation methods
|
||||
internals: ElementInternals;
|
||||
|
||||
assumeInteractionOn: string[] = ['wa-input'];
|
||||
|
||||
// Additional
|
||||
formControl?: HTMLElement & { value: string | FormData | null | File };
|
||||
|
||||
@@ -215,6 +240,8 @@ export class WebAwesomeFormControl extends WebAwesomeElement implements Omit<Ele
|
||||
valueHasChanged: boolean = false;
|
||||
hasInteracted: boolean = false;
|
||||
|
||||
private emittedEvents: string[] = [];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
@@ -223,13 +250,62 @@ export class WebAwesomeFormControl extends WebAwesomeElement implements Omit<Ele
|
||||
} catch (_e) {
|
||||
console.error('Element internals are not supported in your browser. Consider using a polyfill');
|
||||
}
|
||||
|
||||
const ctor = this.constructor as typeof LitElement;
|
||||
|
||||
if (ctor.properties?.disabled?.reflect === true) {
|
||||
console.warn(`The following element has their "disabled" property set to reflect.`);
|
||||
console.warn(this);
|
||||
console.warn('For further reading: https://github.com/whatwg/html/issues/8365');
|
||||
}
|
||||
|
||||
this.addEventListener('invalid', this.emitInvalid);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
// Lazily evaluate after the constructor.
|
||||
this.assumeInteractionOn.forEach(event => {
|
||||
this.addEventListener(event, this.handleInteraction);
|
||||
});
|
||||
}
|
||||
|
||||
emitInvalid = (e: Event) => {
|
||||
if (e.target !== this) return;
|
||||
|
||||
this.emit('wa-invalid');
|
||||
};
|
||||
|
||||
protected willUpdate(changedProperties: PropertyValues<this>) {
|
||||
if (
|
||||
changedProperties.has('formControl') ||
|
||||
changedProperties.has('defaultValue') ||
|
||||
changedProperties.has('value')
|
||||
) {
|
||||
this.setValue(this.value, this.value);
|
||||
}
|
||||
|
||||
super.willUpdate(changedProperties);
|
||||
}
|
||||
|
||||
private handleInteraction = (event: Event) => {
|
||||
const emittedEvents = this.emittedEvents;
|
||||
if (!emittedEvents.includes(event.type)) {
|
||||
emittedEvents.push(event.type);
|
||||
}
|
||||
|
||||
// Mark it as user-interacted as soon as all associated events have been emitted
|
||||
if (emittedEvents.length === this.assumeInteractionOn?.length) {
|
||||
this.hasInteracted = true;
|
||||
}
|
||||
};
|
||||
|
||||
get labels() {
|
||||
return this.internals.labels;
|
||||
}
|
||||
|
||||
get form() {
|
||||
getForm() {
|
||||
return this.internals.form;
|
||||
}
|
||||
|
||||
@@ -264,13 +340,26 @@ export class WebAwesomeFormControl extends WebAwesomeElement implements Omit<Ele
|
||||
}
|
||||
|
||||
setValidity(...args: Parameters<typeof this.internals.setValidity>) {
|
||||
let [flags, message, anchor] = args;
|
||||
const flags = args[0];
|
||||
const message = args[1]
|
||||
let anchor = args[2]
|
||||
|
||||
if (!anchor) {
|
||||
anchor = this.validationTarget;
|
||||
}
|
||||
|
||||
this.internals.setValidity(flags, message, anchor);
|
||||
this.internals.setValidity(flags, message, anchor || undefined);
|
||||
|
||||
const required = Boolean(this.required);
|
||||
const isValid = this.internals.validity.valid;
|
||||
const hasInteracted = this.hasInteracted;
|
||||
|
||||
this.toggleAttribute('data-required', required);
|
||||
this.toggleAttribute('data-optional', !required);
|
||||
this.toggleAttribute('data-invalid', !isValid);
|
||||
this.toggleAttribute('data-valid', isValid);
|
||||
this.toggleAttribute('data-user-invalid', !isValid && hasInteracted);
|
||||
this.toggleAttribute('data-user-valid', isValid && hasInteracted);
|
||||
}
|
||||
|
||||
setCustomValidity(message: string) {
|
||||
@@ -278,7 +367,8 @@ export class WebAwesomeFormControl extends WebAwesomeElement implements Omit<Ele
|
||||
this.setValidity({});
|
||||
return;
|
||||
}
|
||||
this.setValidity({ customError: true }, message);
|
||||
|
||||
this.setValidity({ customError: true }, message, this.validationTarget);
|
||||
}
|
||||
|
||||
formResetCallback() {
|
||||
@@ -290,6 +380,7 @@ export class WebAwesomeFormControl extends WebAwesomeElement implements Omit<Ele
|
||||
this.value = this.defaultValue;
|
||||
this.hasInteracted = false;
|
||||
this.valueHasChanged = false;
|
||||
this.emittedEvents = [];
|
||||
this.runValidators();
|
||||
this.setValue(this.defaultValue, this.defaultValue);
|
||||
}
|
||||
@@ -323,40 +414,40 @@ export class WebAwesomeFormControl extends WebAwesomeElement implements Omit<Ele
|
||||
}
|
||||
|
||||
get allValidators() {
|
||||
const staticValidators = (this.constructor as typeof WebAwesomeFormControl).validators || [];
|
||||
const staticValidators = (this.constructor as typeof WebAwesomeFormAssociated).validators || [];
|
||||
|
||||
const validators = this.validators || [];
|
||||
return [...staticValidators, ...validators];
|
||||
}
|
||||
|
||||
runValidators() {
|
||||
const element = this;
|
||||
|
||||
if (element.disabled || element.getAttribute('disabled')) {
|
||||
element.setValidity({});
|
||||
// We don't run validators on disabled elements to be inline with native HTMLElements.
|
||||
if (this.disabled || this.getAttribute('disabled')) {
|
||||
this.setValidity({});
|
||||
// We don't run validators on disabled thiss to be inline with native HTMLElements.
|
||||
// https://codepen.io/paramagicdev/pen/PoLogeL
|
||||
return;
|
||||
}
|
||||
|
||||
const validators =
|
||||
/** @type {{allValidators?: Array<import("../types.js").Validator>}} */ /** @type {unknown} */ element.allValidators;
|
||||
/** @type {{allValidators?: Array<import("../types.js").Validator>}} */ /** @type {unknown} */ this.allValidators;
|
||||
|
||||
if (!validators) {
|
||||
element.setValidity({});
|
||||
this.setValidity({});
|
||||
return;
|
||||
}
|
||||
|
||||
const flags = {
|
||||
customError: element.validity.customError
|
||||
type ValidityKey = { -readonly [P in keyof ValidityState]: ValidityState[P] }
|
||||
|
||||
const flags: Partial<ValidityKey> = {
|
||||
customError: this.validity.customError
|
||||
};
|
||||
|
||||
const formControl = element.formControl || undefined;
|
||||
const formControl = this.validationTarget || this.formControl || undefined;
|
||||
|
||||
let finalMessage = '';
|
||||
|
||||
for (const validator of validators) {
|
||||
const { isValid, message, invalidKeys } = validator.checkValidity(element);
|
||||
const { isValid, message, invalidKeys } = validator.checkValidity(this);
|
||||
|
||||
if (isValid) {
|
||||
continue;
|
||||
@@ -367,23 +458,23 @@ export class WebAwesomeFormControl extends WebAwesomeElement implements Omit<Ele
|
||||
}
|
||||
|
||||
if (invalidKeys?.length >= 0) {
|
||||
// @ts-expect-error
|
||||
invalidKeys.forEach(str => (flags[str] = true));
|
||||
(invalidKeys as (keyof ValidityState)[]).forEach(str => (flags[str] = true));
|
||||
}
|
||||
}
|
||||
|
||||
// This is a workaround for preserving custom errors
|
||||
if (!finalMessage) {
|
||||
finalMessage = element.validationMessage;
|
||||
finalMessage = this.validationMessage;
|
||||
}
|
||||
element.setValidity(flags, finalMessage, formControl);
|
||||
|
||||
this.setValidity(flags, finalMessage, formControl);
|
||||
}
|
||||
|
||||
// Custom states
|
||||
addCustomState(state: string) {
|
||||
try {
|
||||
// @ts-expect-error
|
||||
this.internals.states.add(state);
|
||||
// @ts-expect-error CustomStateSet doesn't exist in TS yet.
|
||||
(this.internals.states as Set<string>).add(state);
|
||||
} catch (_) {
|
||||
// Without this, test suite errors.
|
||||
} finally {
|
||||
@@ -393,8 +484,8 @@ export class WebAwesomeFormControl extends WebAwesomeElement implements Omit<Ele
|
||||
|
||||
deleteCustomState(state: string) {
|
||||
try {
|
||||
// @ts-expect-error
|
||||
this.internals.states.delete(state);
|
||||
// @ts-expect-error CustomStateSet doesn't exist in TS yet.
|
||||
(this.internals.states as Set<string>).delete(state);
|
||||
} catch (_) {
|
||||
// Without this, test suite errors.
|
||||
} finally {
|
||||
@@ -417,31 +508,19 @@ export class WebAwesomeFormControl extends WebAwesomeElement implements Omit<Ele
|
||||
}
|
||||
|
||||
hasCustomState(state: string) {
|
||||
let bool = false
|
||||
|
||||
try {
|
||||
// @ts-expect-error
|
||||
return this.internals.states.has(state);
|
||||
// @ts-expect-error CustomStateSet doesn't exist in TS yet.
|
||||
bool = (this.internals.states as Set<string>).has(state);
|
||||
} catch (_) {
|
||||
// Without this, test suite errors.
|
||||
} finally {
|
||||
return this.hasAttribute(`data-${state}`);
|
||||
}
|
||||
}
|
||||
|
||||
protected willUpdate(changedProperties: PropertyValueMap<typeof this>): void {
|
||||
// if (changedProperties.has("formControl")) {
|
||||
// this.formControl?.addEventListener("focusout", this.handleInteraction)
|
||||
// this.formControl?.addEventListener("blur", this.handleInteraction)
|
||||
// this.formControl?.addEventListener("click", this.handleInteraction)
|
||||
// }
|
||||
|
||||
if (
|
||||
changedProperties.has('formControl') ||
|
||||
changedProperties.has('defaultValue') ||
|
||||
changedProperties.has('value')
|
||||
) {
|
||||
this.setValue(this.value, this.value);
|
||||
if (!bool) {
|
||||
bool = this.hasAttribute(`data-${state}`);
|
||||
}
|
||||
}
|
||||
|
||||
super.willUpdate(changedProperties);
|
||||
return bool
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user