Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/fields no constraint no validation #996

Merged
merged 51 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
8608309
refactor: remove duplicated error change notification
wattachai-lseg Oct 16, 2023
7ee5547
chore: update playwright
wattachai-lseg Oct 16, 2023
d825acc
feat(text-field): prevent constraint validation if there is none
wattachai-lseg Oct 16, 2023
bf627c4
feat(number-field): prevent constraint validation if there is none
wattachai-lseg Oct 16, 2023
85fbb04
test(number-field): add todo for user interaction test
wattachai-lseg Oct 17, 2023
1b22c88
refactor(email-field): add pattern default value to email field
wattachai-lseg Oct 18, 2023
687eba2
docs(number-field): add custom validation section
wattachai-lseg Oct 18, 2023
2d5eb3e
docs: update example
wattachai-lseg Oct 18, 2023
ffc5f22
docs(email-field): add custom validation section
wattachai-lseg Oct 18, 2023
3a901b4
docs(text-field): fix element reference
wattachai-lseg Oct 18, 2023
519b5b6
refactor: keep default email validation of email field
wattachai-lseg Oct 19, 2023
7a36785
docs(password-field): add custom validation section
wattachai-lseg Oct 19, 2023
b9099d9
docs: add missing pattern attr
wattachai-lseg Oct 19, 2023
2c5bcf4
docs(search-field): add custom validation section
wattachai-lseg Oct 19, 2023
26ea6b6
chore: remove unresolvable todo
wattachai-lseg Oct 19, 2023
9245eb2
refactor: clarify code comment
wattachai-lseg Oct 19, 2023
37d4243
test(text-field): add test cases based on mock user interaction
wattachai-lseg Oct 20, 2023
f178c8c
test(email-field): add test cases covering overridden pattern property
wattachai-lseg Oct 20, 2023
410188e
Merge branch 'v7' into feat/fields-no-contraint-no-validation
wattachai-lseg Oct 20, 2023
df0c78e
test(number-field): add test cases based on mock user interaction
wattachai-lseg Oct 20, 2023
dcf92b4
Merge branch 'v7' into feat/fields-no-contraint-no-validation
wattachai-lseg Oct 20, 2023
e38a9ff
test: clarify test case description
wattachai-lseg Oct 20, 2023
0a98456
Merge remote-tracking branch 'origin/feat/fields-no-contraint-no-vali…
wattachai-lseg Oct 20, 2023
76d42c2
docs: update custom validation description
wattachai-lseg Oct 20, 2023
b51455b
Merge branch 'v7' into feat/fields-no-contraint-no-validation
wattachai-lseg Oct 23, 2023
d1fb5fb
Merge branch 'v7' into feat/fields-no-contraint-no-validation
wsuwt Oct 24, 2023
5416e6a
Merge branch 'v7' into feat/fields-no-contraint-no-validation
wattachai-lseg Oct 26, 2023
f7365cd
refactor: remove @inheritdoc usage
wattachai-lseg Oct 26, 2023
fe5dab3
docs: fix case
wattachai-lseg Oct 26, 2023
d977308
docs: fix import template reference
wattachai-lseg Oct 26, 2023
d1e9bdf
docs(number-field): simplify custom validation example
wattachai-lseg Oct 26, 2023
ad037fe
docs(number-field): align variable name
wattachai-lseg Oct 26, 2023
fc54d77
test(email-field): clarify test case description and its comment
wattachai-lseg Oct 26, 2023
9f6d49d
refactor: revise variable name
wattachai-lseg Oct 26, 2023
38b32a1
docs(email-field): update custom validation description
wattachai-lseg Oct 26, 2023
f57d7b5
Merge remote-tracking branch 'origin/feat/fields-no-contraint-no-vali…
wattachai-lseg Oct 26, 2023
ace6e9e
docs: revise custom validation description
wattachai-lseg Oct 26, 2023
b492b4d
docs: avoid double negative caused by variable naming
wattachai-lseg Oct 26, 2023
2f3bcfe
refactor: remove unnecessary hasChanged option in @property decorators
wattachai-lseg Oct 26, 2023
deb2f28
refactor: workaround missing attribute from component doc with override
wattachai-lseg Oct 26, 2023
aaca9b3
refactor: allocate space for error message with css
wattachai-lseg Oct 26, 2023
2f0db40
Merge branch 'v7' into feat/fields-no-contraint-no-validation
wattachai-lseg Oct 26, 2023
f885b19
docs: revise variable naming of examples
wattachai-lseg Oct 26, 2023
adf6734
Merge branch 'v7' into feat/fields-no-contraint-no-validation
wattachai-lseg Oct 26, 2023
1037911
docs: update heading case style following lit doc
wattachai-lseg Oct 27, 2023
f311f49
docs: remove redundant Boolean usage
wattachai-lseg Oct 27, 2023
f283548
Merge branch 'v7' into feat/fields-no-contraint-no-validation
wattachai-lseg Oct 30, 2023
c0dcc21
Merge branch 'v7' into feat/fields-no-contraint-no-validation
wsuwt Oct 31, 2023
08110cc
docs: revise heading case style
wattachai-lseg Nov 2, 2023
8fe2f31
chore(create-efx): revise heading case style template
wattachai-lseg Nov 2, 2023
38a6587
Merge branch 'v7' into feat/fields-no-contraint-no-validation
wattachai-lseg Nov 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion documents/scripts/element.injector.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const handler = async () => {
const hasApi = apiReferenceIndices.some(index => index !== -1);

if(hasApi) {
content += '\n\n---\n' + '\n## API Reference\n';
content += '\n\n---\n' + '\n## API reference\n';
}

for(let i=0; i<apiReferenceIndices.length; i++) {
Expand Down
167 changes: 164 additions & 3 deletions documents/src/pages/elements/email-field.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ p {
</ef-email-field>
```

## Getting value
## Getting a value
The field's value can be accessed directly using the `value` property.

```html
Expand Down Expand Up @@ -197,7 +197,7 @@ emailField?.addEventListener("input", () => {
});
```

### Use pattern
### Using a pattern
You can use a regular expression to validate the input value by adding the `pattern` attribute.

::
Expand Down Expand Up @@ -283,7 +283,168 @@ emailField?.addEventListener("input", () => {
});
```

## Show icon
### Custom validation

For advance use cases, default validation and error state of the field can be overridden. To do this, make sure that `maxLength` & `minLength` are not set and `pattern` is set to `''`, then validate with your customised validation logic and update `error` property accordingly.

::

```javascript
::text-field::
const fullName = document.getElementById("full-name");
const email = document.getElementById("email");
const responseText = document.getElementById("response-text");
wsuwt marked this conversation as resolved.
Show resolved Hide resolved
const save = document.getElementById("button");

save.addEventListener("tap", () => {
const isPartial = Boolean(fullName.value) !== Boolean(email.value);
fullName.error = isPartial ? !fullName.value : false;
email.error = isPartial ? !email.value : false;
if (isPartial) {
responseText.classList.add('error');
responseText.innerHTML = "Full name & email must be provided together";
wattachai-lseg marked this conversation as resolved.
Show resolved Hide resolved
} else if (email.value && !/^\[email protected]$/.test(email.value)) {
email.error = true;
responseText.innerHTML = "Email must be valid and end with @mail.com";
} else {
responseText.innerHTML = "Saved";
}
});

const inputHandler = () => {
responseText.classList.remove('error');
fullName.error = false;
email.error = false;
responseText.innerHTML = "";
};

fullName.addEventListener("input", inputHandler);
email.addEventListener("input", inputHandler);
```

```css
.error {
color: #d94255;
}
ef-text-field, ef-email-field {
width: 250px;
}
label {
display: block;
}

#response-text {
min-height: 18px;
}
```

```html
<p>Please provide secondary contact if available</p>
<label for="full-name">Full name</label>
<ef-text-field
id="full-name"
aria-describedby="response-text"
placeholder="Full name as shown on the passport">
</ef-text-field>
<label for="email">Email</label>
<ef-email-field
id="email"
aria-describedby="response-text"
placeholder="Actively used email address">
</ef-email-field>
<p id="response-text"></p>
<ef-button id="button">Save</ef-button>
```

::

```html
<p>Please provide secondary contact if available</p>
<label for="full-name">Full name</label>
<ef-text-field
id="full-name"
aria-describedby="response-text"
placeholder="Full name as shown on the passport">
</ef-text-field>
<label for="email">Email</label>
<ef-email-field
id="email"
aria-describedby="response-text"
placeholder="Actively used email address">
</ef-email-field>
<p id="response-text"></p>
<ef-button id="button">Save</ef-button>
```

```javascript
const fullName = document.getElementById("full-name");
const email = document.getElementById("email");
const responseText = document.getElementById("response-text");
const save = document.getElementById("button");

save.addEventListener("tap", () => {
const isPartial = Boolean(fullName.value) !== Boolean(email.value);
fullName.error = isPartial ? !fullName.value : false;
email.error = isPartial ? !email.value : false;
if (isPartial) {
responseText.classList.add('error');
responseText.innerHTML = "Full name & email must be provided together";
} else if (email.value && !/^\[email protected]$/.test(email.value)) {
email.error = true;
responseText.innerHTML = "Email must be valid and end with @mail.com";
} else {
responseText.innerHTML = "Saved";
}
});

const inputHandler = () => {
responseText.classList.remove('error');
fullName.error = false;
email.error = false;
responseText.innerHTML = "";
};

fullName.addEventListener("input", inputHandler);
email.addEventListener("input", inputHandler);
```

```typescript
import type { TextField } from "@refinitiv-ui/elements/text-field";
import type { EmailField } from "@refinitiv-ui/elements/email-field";
import type { Button } from "@refinitiv-ui/elements/button";

const fullName = document.getElementById("full-name") as TextField;
const email = document.getElementById("email") as EmailField;
const responseText = document.getElementById("response-text") as HTMLElement;
const save = document.getElementById("button") as Button;

save.addEventListener("tap", () => {
const isPartial = Boolean(fullName.value) !== Boolean(email.value);
fullName.error = isPartial ? !fullName.value : false;
email.error = isPartial ? !email.value : false;
if (isPartial) {
responseText.classList.add('error');
responseText.innerHTML = "Full name & email must be provided together";
} else if (email.value && !/^\[email protected]$/.test(email.value)) {
email.error = true;
responseText.innerHTML = "Email must be valid and end with @mail.com";
} else {
responseText.innerHTML = "Saved";
}
});

const inputHandler = () => {
responseText.classList.remove('error');
fullName.error = false;
email.error = false;
responseText.innerHTML = "";
};

fullName.addEventListener("input", inputHandler);
email.addEventListener("input", inputHandler);
```

## Showing an icon
An inline icon can be displayed inside the input using `icon`.

```html
Expand Down
159 changes: 156 additions & 3 deletions documents/src/pages/elements/number-field.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Number field can be used in a similar fashion to the native number input.
<ef-number-field id="total" value="1000"></ef-number-field>
```

## Getting value
## Getting a value
Just like the HTML native input, the number field input value is a `string` which can be accessed using the `value` property.

```html
Expand Down Expand Up @@ -204,7 +204,7 @@ numberField?.addEventListener("input", () => {
});
```

### Set min or max
### Setting min or max
Minimum and maximum values can be set to limit input values when the user interacts. If a value exceeds the min or max set programmatically, the component will display an error state.

```html
Expand All @@ -216,7 +216,7 @@ Minimum and maximum values can be set to limit input values when the user intera
</ef-number-field>
```

### Set input step
### Setting input step
The step attribute specifies the interval between valid numbers. For instance, when `step="2"`, valid values would only be even numbers e.g. 2,4,6,8... Alternatively, specify the `step="any"` to allow any value.

::
Expand Down Expand Up @@ -246,6 +246,159 @@ The step attribute specifies the interval between valid numbers. For instance, w
<ef-number-field id="any" step="any"></ef-number-field>
```

### Custom validation

For advance use cases, default validation and error state of the field can be overridden. To do this, make sure that `max` & `min` are not set and `step` is set to `any`, then validate with your customised validation logic and update `error` property accordingly.

::

```javascript
::number-field::
const numberField = document.getElementById("prime-number");
const errorText = document.getElementById("error-text");

const isPrime = (n) => {
if (n <= 1) {
return false;
}

if (n === 2 || n === 3) {
return true;
}

for (let i = 2; i <= Math.sqrt(n); i++) {
if (n % i === 0) {
return false;
}
}
return true;
};

numberField.addEventListener("blur", () => {
const value = Number(numberField.value);
const error = !isPrime(value);
numberField.error = error;
errorText.textContent = error ? "Start value must be a prime number" : "";
});

numberField.addEventListener("input", () => {
const value = Number(numberField.value);
if (isPrime(value)) {
errorText.textContent = "";
}
});
```

```css
#error-text {
color:#d94255;
}
ef-number-field {
width: 250px;
}
label {
display: block;
}
```

```html
<label for="prime-number">Prime number</label>
<ef-number-field
id="prime-number"
aria-describedby="error-text"
step="any"
placeholder="Please input a prime number">
</ef-number-field>
<p id="error-text"></p>
```

::

```html
<label for="prime-number">Start value</label>
<ef-number-field
id="prime-number"
aria-describedby="error-text"
step="any"
placeholder="any prime number such as 2, 3 and 5">
</ef-number-field>
<p id="error-text"></p>
```

```javascript
const numberField = document.getElementById("prime-number");
const errorText = document.getElementById("error-text");

const isPrime = (n) => {
if (n <= 1) {
return false;
}

if (n === 2 || n === 3) {
return true;
}

for (let i = 2; i <= Math.sqrt(n); i++) {
if (n % i === 0) {
return false;
}
}
return true;
};

numberField.addEventListener("blur", () => {
const value = Number(numberField.value);
const error = !isPrime(value);
numberField.error = error;
errorText.textContent = error ? "Start value must be a prime number" : "";
});

numberField.addEventListener("input", () => {
const value = Number(numberField.value);
if (isPrime(value)) {
errorText.textContent = "";
}
});
```

```typescript
import type { NumberField } from "@refinitiv-ui/elements/number-field";

const numberField = document.getElementById("prime-number") as NumberField;
const errorText = document.getElementById("error-text") as HTMLElement;

const isPrime = (n: number) => {
if (n <= 1) {
return false;
}

if (n === 2 || n === 3) {
return true;
}

for (let i = 2; i <= Math.sqrt(n); i++) {
if (n % i === 0) {
return false;
}
}
return true;
};

numberField.addEventListener("blur", () => {
const value = Number(numberField.value);
const error = !isPrime(value);
numberField.error = error;
errorText.textContent = error ? "Start value must be a prime number" : "";
});

numberField.addEventListener("input", () => {
const value = Number(numberField.value);
if (isPrime(value)) {
errorText.textContent = "";
}
});
```

## Accessibility
::a11y-intro::

Expand Down
Loading
Loading