-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
135 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
--- | ||
"@sjsf/daisyui-theme": patch | ||
"playground": patch | ||
"@sjsf/form": patch | ||
"docs": patch | ||
--- | ||
|
||
Add `focusOnFirstError` feature |
24 changes: 24 additions & 0 deletions
24
apps/docs/src/content/docs/customization/focus-on-first-error.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
--- | ||
title: Focus on first error | ||
sidebar: | ||
order: 2 | ||
--- | ||
|
||
You can achieve focus on the first error by using the `focusOnFirstError` function. | ||
|
||
## Usage | ||
|
||
```svelte | ||
<script lang="ts"> | ||
import { Form } from "@sjsf/form"; | ||
import { focusOnFirstError } from '@sjsf/form/focus-on-first-error'; | ||
</script> | ||
<Form {...} onSubmitError={focusOnFirstError} /> | ||
``` | ||
|
||
## Explanation | ||
|
||
1. `focusOnFirstError` will try to find a focusable element and focus it. | ||
2. If it's not found, it will try to find an errors list and scroll it into view. | ||
3. If it's not found, it will return `false`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { tick } from "svelte"; | ||
|
||
import { | ||
ValidatorErrorType, | ||
type ValidatorError, | ||
type ValidationError, | ||
} from "@/core/validator.js"; | ||
|
||
export function getFocusableElement( | ||
form: HTMLElement, | ||
error: ValidationError<unknown> | ||
) { | ||
const item = form.querySelector(`[id="${error.instanceId}"]`); | ||
if ( | ||
!( | ||
(item instanceof HTMLInputElement && item.type !== "checkbox") || | ||
item instanceof HTMLTextAreaElement || | ||
item instanceof HTMLSelectElement || | ||
item instanceof HTMLButtonElement | ||
) | ||
) { | ||
return null; | ||
} | ||
return item; | ||
} | ||
|
||
export function getErrorsList( | ||
form: HTMLElement, | ||
error: ValidationError<unknown> | ||
) { | ||
return form.querySelector(`[data-errors-for="${error.instanceId}"]`); | ||
} | ||
|
||
export function getFocusAction( | ||
form: HTMLElement, | ||
error: ValidationError<unknown> | ||
) { | ||
const focusableElement = getFocusableElement(form, error); | ||
if (focusableElement !== null) { | ||
return () => focusableElement.focus(); | ||
} | ||
const errorsList = getErrorsList(form, error); | ||
if (errorsList !== null) { | ||
return () => | ||
errorsList.scrollIntoView({ behavior: "auto", block: "center" }); | ||
} | ||
return null; | ||
} | ||
|
||
export function focusOnFirstError( | ||
errors: ValidatorError<unknown>[], | ||
e: SubmitEvent | ||
) { | ||
const form = e.target; | ||
if (!(form instanceof HTMLElement)) { | ||
console.warn("Expected form to be an HTMLFormElement, got", form); | ||
return false; | ||
} | ||
const error = errors.find( | ||
(err) => err.type === ValidatorErrorType.ValidationError | ||
); | ||
if (!error) { | ||
return false; | ||
} | ||
const focusAction = getFocusAction(form, error); | ||
if (focusAction === null) { | ||
return false; | ||
} | ||
// NOTE: We use tick here because new errors may produce layout changes. | ||
return tick().then(focusAction); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters