Skip to content

Commit

Permalink
feat(textarea): add error state management
Browse files Browse the repository at this point in the history
  • Loading branch information
dpellier committed Nov 28, 2024
1 parent 42cbc3c commit 1214318
Show file tree
Hide file tree
Showing 14 changed files with 434 additions and 189 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export class OdsInput {

// We set the value before the observer starts to avoid calling the mutation callback twice
// as it will be called on componentDidLoad (when native element validity is up-to-date)
if (!this.value && (this.value !== VALUE_DEFAULT_VALUE || this.defaultValue)) {
if (!this.value && this.value !== 0 && (this.value !== VALUE_DEFAULT_VALUE || this.defaultValue)) {
this.value = this.defaultValue ?? null;
}
}
Expand Down Expand Up @@ -189,7 +189,7 @@ export class OdsInput {

this.odsChange.emit({
name: this.name,
previousValue,
previousValue, // TODO always string if coming from mutation oldValue => need to parse if type number
validity: this.internals.validity,
value: this.value,
});
Expand Down
4 changes: 2 additions & 2 deletions packages/ods/src/components/input/src/controller/ods-input.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { setInternalsValidity } from '../../../../utils/dom';
import { setInternalsValidityFromHtmlElement } from '../../../../utils/dom';

async function handleKeySpaceEnter(event: KeyboardEvent, isDisabled: boolean, callback: () => Promise<void>): Promise<void> {
event.preventDefault();
Expand All @@ -16,7 +16,7 @@ function updateInternals(internals: ElementInternals, value: number | string | n
internals.setFormValue(value?.toString() ?? '');

if (inputEl) {
setInternalsValidity(inputEl, internals);
setInternalsValidityFromHtmlElement(inputEl, internals);
}
}

Expand Down
53 changes: 29 additions & 24 deletions packages/ods/src/components/input/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -80,43 +80,48 @@

<p>Form</p>
<form id="input-form">
<ods-input default-value="On Vous Heberge ?"
id="input-form-input"
<label for="input-form-first-name">First name:</label>
<ods-input id="input-form-first-name"
is-required
name="ods-input"
value="">
name="firstName">
</ods-input>

<label for="input-form-last-name">Last name:</label>
<ods-input id="input-form-last-name"
is-required
name="lastName">
</ods-input>

<!-- <input type="text" name="natif-input" required>-->

<button id="input-form-check-validity-button" type="button">Check validity</button>
<button id="input-form-clear-button" type="button">Clear</button>
<button id="input-form-reset-button" type="button">Reset</button>
<button type="reset">Global Form Reset</button>
<!-- <button id="input-form-check-validity-button" type="button">Check validity</button>-->
<!-- <button id="input-form-clear-button" type="button">Clear</button>-->
<!-- <button id="input-form-reset-button" type="button">Reset</button>-->
<!-- <button type="reset">Global Form Reset</button>-->
<button id="input-form-submit-button" type="submit">Submit</button>
</form>
<script>
const formElement = document.querySelector('#input-form');
const inputFormInput = document.querySelector('#input-form-input');
const inputCheckValidityFormButton = document.querySelector('#input-form-check-validity-button');
const inputClearFormButton = document.querySelector('#input-form-clear-button');
const inputResetFormButton = document.querySelector('#input-form-reset-button');
// const inputFormInput = document.querySelector('#input-form-input');
// const inputCheckValidityFormButton = document.querySelector('#input-form-check-validity-button');
// const inputClearFormButton = document.querySelector('#input-form-clear-button');
// const inputResetFormButton = document.querySelector('#input-form-reset-button');
const inputSubmitFormButton = document.querySelector('#input-form-submit-button');

inputCheckValidityFormButton.addEventListener('click', async() => {
console.log('Check validity: ', await inputFormInput.checkValidity());
});

inputClearFormButton.addEventListener('click', async() => {
await inputFormInput.clear();
});

inputResetFormButton.addEventListener('click', async() => {
await inputFormInput.reset();
});
// inputCheckValidityFormButton.addEventListener('click', async() => {
// console.log('Check validity: ', await inputFormInput.checkValidity());
// });
//
// inputClearFormButton.addEventListener('click', async() => {
// await inputFormInput.clear();
// });
//
// inputResetFormButton.addEventListener('click', async() => {
// await inputFormInput.reset();
// });

inputSubmitFormButton.addEventListener('click', (e) => {
e.preventDefault(); // comment to test native validation messages
// e.preventDefault(); // comment to test native validation messages
const formData = new FormData(formElement);
console.log('formData', formData);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { submitFormOnEnter } from '../../../../../utils/dom';
import { ODS_BUTTON_COLOR, ODS_BUTTON_SIZE, ODS_BUTTON_VARIANT } from '../../../../button/src';
import { ODS_ICON_NAME } from '../../../../icon/src';
import { ODS_INPUT_TYPE, type OdsInput, type OdsInputChangeEvent } from '../../../../input/src';
import { isMinusButtonDisabled, isPlusButtonDisabled, setFormValue } from '../../controller/ods-quantity';
import { isMinusButtonDisabled, isPlusButtonDisabled, updateInternals } from '../../controller/ods-quantity';
import { type OdsQuantityChangeEventDetail } from '../../interfaces/events';

const VALUE_DEFAULT_VALUE = null;

@Component({
formAssociated: true,
shadow: {
Expand All @@ -15,7 +17,7 @@ import { type OdsQuantityChangeEventDetail } from '../../interfaces/events';
tag: 'ods-quantity',
})
export class OdsQuantity {
private odsInput?: OdsInput;
private odsInput?: HTMLElement & OdsInput;

@AttachInternals() internals!: ElementInternals;

Expand All @@ -31,7 +33,7 @@ export class OdsQuantity {
@Prop({ reflect: true }) public name!: string;
@Prop({ reflect: true }) public placeholder?: string;
@Prop({ reflect: true }) public step?: number;
@Prop({ mutable: true, reflect: true }) public value: number | null = null;
@Prop({ mutable: true, reflect: true }) public value: number | null = VALUE_DEFAULT_VALUE;

@Event() odsBlur!: EventEmitter<void>;
@Event() odsChange!: EventEmitter<OdsQuantityChangeEventDetail>;
Expand All @@ -40,25 +42,39 @@ export class OdsQuantity {
@Event() odsReset!: EventEmitter<void>;

@Method()
public async clear(): Promise<void> {
async checkValidity(): Promise<boolean> {
return this.internals.checkValidity();
}

@Method()
async clear(): Promise<void> {
return this.odsInput?.clear();
}

@Method()
public async getValidity(): Promise<ValidityState | undefined> {
async getValidity(): Promise<ValidityState | undefined> {
return this.odsInput?.getValidity();
}

@Method()
public async reset(): Promise<void> {
async reset(): Promise<void> {
return this.odsInput?.reset();
}

componentWillLoad(): void {
if (!this.value && this.value !== 0) {
// if (!this.value && this.value !== 0) {
// this.value = this.defaultValue ?? null;
// }
// setFormValue(this.internals, this.value);

if (!this.value && this.value !== 0 && (this.value !== VALUE_DEFAULT_VALUE || this.defaultValue)) {
this.value = this.defaultValue ?? null;
}
setFormValue(this.internals, this.value);
}

async componentDidLoad(): Promise<void> {
// const validityState = await this.odsInput?.getValidity()
await updateInternals(this.internals, this.value, this.odsInput);
}

async formResetCallback(): Promise<void> {
Expand All @@ -81,13 +97,14 @@ export class OdsQuantity {
this.value = this.value !== null ? Number(this.value) + step : 0;
}

private onOdsChange(event: OdsInputChangeEvent): void {
private async onOdsChange(event: OdsInputChangeEvent): Promise<void> {
if (event.detail.value === null) {
this.value = null;
} else {
this.value = Number(event.detail.value) ?? null;
}
setFormValue(this.internals, this.value);
// setFormValue(this.internals, this.value);
await updateInternals(this.internals, this.value, this.odsInput);
}

render(): FunctionalComponent {
Expand Down Expand Up @@ -121,7 +138,7 @@ export class OdsQuantity {
min={ this.min }
name={ this.name }
placeholder={ this.placeholder }
ref={ (el?: unknown) => this.odsInput = el as OdsInput }
ref={ (el?: unknown) => this.odsInput = el as HTMLElement & OdsInput }
step={ this.step }
type={ ODS_INPUT_TYPE.number }
value={ this.value }>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
function isPlusButtonDisabled(isDisabled: boolean, isReadonly: boolean, value: number | null, max?: number): boolean {
return isDisabled || isReadonly || (max !== undefined && value !== null && max <= value);
}
import { setInternalsValidityFromOdsComponent } from '../../../../utils/dom';
import { type OdsInput } from '../../../input/src';

function isMinusButtonDisabled(isDisabled: boolean, isReadonly: boolean, value: number | null, min?: number): boolean {
return isDisabled || isReadonly || (min !== undefined && value !== null && min >= value);
}

function setFormValue(internals: ElementInternals, value: number | null): void {
function isPlusButtonDisabled(isDisabled: boolean, isReadonly: boolean, value: number | null, max?: number): boolean {
return isDisabled || isReadonly || (max !== undefined && value !== null && max <= value);
}

//function updateInternals(internals: ElementInternals, value: number | string | null, inputEl?: HTMLInputElement): void {
async function updateInternals(internals: ElementInternals, value: number | string | null, inputEl?: HTMLElement & OdsInput): Promise<void> {
internals.setFormValue(value?.toString() ?? '');

if (inputEl) {
await setInternalsValidityFromOdsComponent(inputEl, internals);
}
}

export {
isPlusButtonDisabled,
isMinusButtonDisabled,
setFormValue,
isPlusButtonDisabled,
updateInternals,
};
Loading

0 comments on commit 1214318

Please sign in to comment.