diff --git a/docs/app/components/content/examples/button/ButtonLoadingAutoExample.vue b/docs/app/components/content/examples/button/ButtonLoadingAutoExample.vue
new file mode 100644
index 0000000000..0545863691
--- /dev/null
+++ b/docs/app/components/content/examples/button/ButtonLoadingAutoExample.vue
@@ -0,0 +1,11 @@
+
+
+
+
+ Button
+
+
diff --git a/docs/app/components/content/examples/button/ButtonLoadingAutoFormExample.vue b/docs/app/components/content/examples/button/ButtonLoadingAutoFormExample.vue
new file mode 100644
index 0000000000..cefd2a558e
--- /dev/null
+++ b/docs/app/components/content/examples/button/ButtonLoadingAutoFormExample.vue
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+ Submit
+
+
+
diff --git a/docs/app/components/content/examples/form/FormExampleElements.vue b/docs/app/components/content/examples/form/FormExampleElements.vue
index 671eee7a28..b7283ffe5b 100644
--- a/docs/app/components/content/examples/form/FormExampleElements.vue
+++ b/docs/app/components/content/examples/form/FormExampleElements.vue
@@ -103,11 +103,11 @@ async function onSubmit(event: FormSubmitEvent) {
-
+
Submit
-
+
Clear
diff --git a/docs/app/components/content/examples/form/FormExampleNested.vue b/docs/app/components/content/examples/form/FormExampleNested.vue
index 932eb34fd7..dd291084a0 100644
--- a/docs/app/components/content/examples/form/FormExampleNested.vue
+++ b/docs/app/components/content/examples/form/FormExampleNested.vue
@@ -29,7 +29,7 @@ async function onSubmit(event: FormSubmitEvent) {
:state="state"
:schema="schema"
class="gap-4 flex flex-col w-60"
- @submit="(event) => onSubmit(event)"
+ @submit="onSubmit"
>
diff --git a/docs/app/components/content/examples/form/FormExampleOnError.vue b/docs/app/components/content/examples/form/FormExampleOnError.vue
index 26b0cf6acf..8bf1a8ee88 100644
--- a/docs/app/components/content/examples/form/FormExampleOnError.vue
+++ b/docs/app/components/content/examples/form/FormExampleOnError.vue
@@ -20,9 +20,11 @@ async function onSubmit(event: FormSubmitEvent) {
}
async function onError(event: FormErrorEvent) {
- const element = document.getElementById(event.errors[0].id)
- element?.focus()
- element?.scrollIntoView({ behavior: 'smooth', block: 'center' })
+ if (event?.errors?.[0]?.id) {
+ const element = document.getElementById(event.errors[0].id)
+ element?.focus()
+ element?.scrollIntoView({ behavior: 'smooth', block: 'center' })
+ }
}
diff --git a/docs/app/components/content/examples/form/FormExampleZod.vue b/docs/app/components/content/examples/form/FormExampleZod.vue
index f838729bf3..d88ed2add0 100644
--- a/docs/app/components/content/examples/form/FormExampleZod.vue
+++ b/docs/app/components/content/examples/form/FormExampleZod.vue
@@ -9,7 +9,7 @@ const schema = z.object({
type Schema = z.output
-const state = reactive({
+const state = reactive>({
email: undefined,
password: undefined
})
diff --git a/docs/content/3.components/button.md b/docs/content/3.components/button.md
index a0bbb2e336..ddcf1588fa 100644
--- a/docs/content/3.components/button.md
+++ b/docs/content/3.components/button.md
@@ -140,7 +140,6 @@ props:
slots:
default: Button
---
-
Button
::
@@ -148,6 +147,14 @@ Button
You can customize this icon globally in your `app.config.ts` under `ui.icons.loading` key.
::
+Use the `loading-auto` prop to show the loading icon automatically while the `@click` promise is pending.
+
+:component-example{name="button-loading-auto-example"}
+
+This also works with the [Form](/components/form) component.
+
+:component-example{name="button-loading-auto-form-example"}
+
### Disabled
Use the `disabled` prop to disable the Button.
diff --git a/playground/app/components/FormNestedExample.vue b/playground/app/components/FormNestedExample.vue
index a6edd42849..5ef7d25962 100644
--- a/playground/app/components/FormNestedExample.vue
+++ b/playground/app/components/FormNestedExample.vue
@@ -35,8 +35,8 @@ function onError(event: any) {
:state="state"
:schema="schema"
class="gap-4 flex flex-col w-60"
- @submit="(event) => onSubmit(event)"
- @error="(event) => onError(event)"
+ @submit="onSubmit"
+ @error="onError"
>
diff --git a/playground/app/pages/components/button.vue b/playground/app/pages/components/button.vue
index 8b1ff50f92..02587d19bc 100644
--- a/playground/app/pages/components/button.vue
+++ b/playground/app/pages/components/button.vue
@@ -4,6 +4,10 @@ import theme from '#build/ui/button'
const sizes = Object.keys(theme.variants.size) as Array
const variants = Object.keys(theme.variants.variant) as Array
+
+function onClick() {
+ return new Promise(res => setTimeout(res, 5000))
+}
@@ -23,7 +27,7 @@ const variants = Object.keys(theme.variants.variant) as Array
-
+
Loading
diff --git a/playground/app/pages/components/form.vue b/playground/app/pages/components/form.vue
index e4e20c045a..aff75d1ab6 100644
--- a/playground/app/pages/components/form.vue
+++ b/playground/app/pages/components/form.vue
@@ -25,7 +25,7 @@ function onSubmit(event: FormSubmitEvent) {
:state="state"
:schema="schema"
class="gap-4 flex flex-col w-60"
- @submit="(event) => onSubmit(event)"
+ @submit="onSubmit"
>
@@ -51,7 +51,7 @@ function onSubmit(event: FormSubmitEvent) {
:schema="schema"
class="gap-4 flex flex-col w-60"
:validate-on-input-delay="2000"
- @submit="(event) => onSubmit(event)"
+ @submit="onSubmit"
>
diff --git a/src/runtime/components/Button.vue b/src/runtime/components/Button.vue
index 1c609a8cee..fbec6fb6be 100644
--- a/src/runtime/components/Button.vue
+++ b/src/runtime/components/Button.vue
@@ -6,6 +6,7 @@ import theme from '#build/ui/button'
import type { LinkProps } from './Link.vue'
import type { UseComponentIconsProps } from '../composables/useComponentIcons'
import type { PartialString } from '../types/utils'
+import { formLoadingInjectionKey } from '../composables/useFormField'
const appConfig = _appConfig as AppConfig & { ui: { button: Partial } }
@@ -22,6 +23,9 @@ export interface ButtonProps extends UseComponentIconsProps, Omit void | Promise
class?: any
ui?: PartialString
}
@@ -34,7 +38,7 @@ export interface ButtonSlots {
-
+
diff --git a/src/runtime/components/Form.vue b/src/runtime/components/Form.vue
index f621d6381e..a07ee81ff6 100644
--- a/src/runtime/components/Form.vue
+++ b/src/runtime/components/Form.vue
@@ -13,11 +13,12 @@ export interface FormProps {
id?: string | number
schema?: FormSchema
state: Partial
- validate?: (state: Partial) => Promise
+ validate?: (state: Partial) => Promise | FormError[]
validateOn?: FormInputEvents[]
disabled?: boolean
validateOnInputDelay?: number
class?: any
+ onSubmit?: ((event: FormSubmitEvent) => void | Promise) | (() => void | Promise)
}
export interface FormEmits {
@@ -31,9 +32,9 @@ export interface FormSlots {
@@ -220,7 +231,7 @@ defineExpose