@byyuurin/ui 0.0.10 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/module.json +3 -3
- package/dist/module.mjs +1 -1
- package/dist/module.mjs.map +1 -1
- package/dist/runtime/app/injections.d.ts +388 -364
- package/dist/runtime/components/Accordion.vue +38 -67
- package/dist/runtime/components/Accordion.vue.d.ts +52 -0
- package/dist/runtime/components/Alert.vue +37 -75
- package/dist/runtime/components/Alert.vue.d.ts +59 -0
- package/dist/runtime/components/App.vue +25 -40
- package/dist/runtime/components/App.vue.d.ts +24 -0
- package/dist/runtime/components/Avatar.vue +31 -51
- package/dist/runtime/components/Avatar.vue.d.ts +25 -0
- package/dist/runtime/components/AvatarGroup.vue +38 -69
- package/dist/runtime/components/AvatarGroup.vue.d.ts +27 -0
- package/dist/runtime/components/Badge.vue +25 -51
- package/dist/runtime/components/Badge.vue.d.ts +44 -0
- package/dist/runtime/components/Breadcrumb.vue +36 -74
- package/dist/runtime/components/Breadcrumb.vue.d.ts +52 -0
- package/dist/runtime/components/Button.vue +62 -51
- package/dist/runtime/components/Button.vue.d.ts +29 -0
- package/dist/runtime/components/ButtonGroup.vue +17 -37
- package/dist/runtime/components/ButtonGroup.vue.d.ts +26 -0
- package/dist/runtime/components/Calendar.vue +75 -110
- package/dist/runtime/components/Calendar.vue.d.ts +75 -0
- package/dist/runtime/components/Card.vue +25 -42
- package/dist/runtime/components/Card.vue.d.ts +30 -0
- package/dist/runtime/components/Carousel.vue +118 -225
- package/dist/runtime/components/Carousel.vue.d.ts +104 -0
- package/dist/runtime/components/Checkbox.vue +46 -73
- package/dist/runtime/components/Checkbox.vue.d.ts +56 -0
- package/dist/runtime/components/Chip.vue +31 -48
- package/dist/runtime/components/Chip.vue.d.ts +30 -0
- package/dist/runtime/components/Collapsible.vue +22 -30
- package/dist/runtime/components/Collapsible.vue.d.ts +26 -0
- package/dist/runtime/components/Drawer.vue +51 -101
- package/dist/runtime/components/Drawer.vue.d.ts +80 -0
- package/dist/runtime/components/DropdownMenu.vue +37 -115
- package/dist/runtime/components/DropdownMenu.vue.d.ts +99 -0
- package/dist/runtime/components/DropdownMenuContent.vue +81 -77
- package/dist/runtime/components/DropdownMenuContent.vue.d.ts +39 -0
- package/dist/runtime/components/Form.vue +140 -254
- package/dist/runtime/components/Form.vue.d.ts +78 -0
- package/dist/runtime/components/FormItem.vue +50 -89
- package/dist/runtime/components/FormItem.vue.d.ts +60 -0
- package/dist/runtime/components/Input.vue +79 -115
- package/dist/runtime/components/Input.vue.d.ts +64 -0
- package/dist/runtime/components/InputNumber.vue +74 -117
- package/dist/runtime/components/InputNumber.vue.d.ts +245 -0
- package/dist/runtime/components/Kbd.vue +18 -39
- package/dist/runtime/components/Kbd.vue.d.ts +28 -0
- package/dist/runtime/components/Link.vue +168 -257
- package/dist/runtime/components/Link.vue.d.ts +95 -0
- package/dist/runtime/components/LinkBase.vue +36 -54
- package/dist/runtime/components/LinkBase.vue.d.ts +28 -0
- package/dist/runtime/components/Modal.vue +49 -84
- package/dist/runtime/components/Modal.vue.d.ts +66 -0
- package/dist/runtime/components/OverlayProvider.vue +10 -14
- package/dist/runtime/components/OverlayProvider.vue.d.ts +2 -0
- package/dist/runtime/components/Pagination.vue +55 -121
- package/dist/runtime/components/Pagination.vue.d.ts +93 -0
- package/dist/runtime/components/PinInput.vue +49 -58
- package/dist/runtime/components/PinInput.vue.d.ts +35 -0
- package/dist/runtime/components/Popover.vue +39 -68
- package/dist/runtime/components/Popover.vue.d.ts +45 -0
- package/dist/runtime/components/Progress.vue +68 -120
- package/dist/runtime/components/Progress.vue.d.ts +54 -0
- package/dist/runtime/components/RadioGroup.vue +67 -125
- package/dist/runtime/components/RadioGroup.vue.d.ts +74 -0
- package/dist/runtime/components/ScrollArea.vue +31 -31
- package/dist/runtime/components/ScrollArea.vue.d.ts +17 -0
- package/dist/runtime/components/Select.vue +114 -204
- package/dist/runtime/components/Select.vue.d.ts +119 -0
- package/dist/runtime/components/Separator.vue +26 -44
- package/dist/runtime/components/Separator.vue.d.ts +27 -0
- package/dist/runtime/components/Skeleton.vue +12 -21
- package/dist/runtime/components/Skeleton.vue.d.ts +19 -0
- package/dist/runtime/components/Slider.vue +52 -74
- package/dist/runtime/components/Slider.vue.d.ts +36 -0
- package/dist/runtime/components/Switch.vue +51 -71
- package/dist/runtime/components/Switch.vue.d.ts +49 -0
- package/dist/runtime/components/Table.vue +108 -194
- package/dist/runtime/components/Table.vue.d.ts +148 -0
- package/dist/runtime/components/Tabs.vue +36 -81
- package/dist/runtime/components/Tabs.vue.d.ts +65 -0
- package/dist/runtime/components/Textarea.vue +77 -124
- package/dist/runtime/components/Textarea.vue.d.ts +60 -0
- package/dist/runtime/components/Toast.vue +47 -75
- package/dist/runtime/components/Toast.vue.d.ts +131 -0
- package/dist/runtime/components/ToastProvider.vue +65 -101
- package/dist/runtime/components/ToastProvider.vue.d.ts +38 -0
- package/dist/runtime/components/Tooltip.vue +36 -47
- package/dist/runtime/components/Tooltip.vue.d.ts +31 -0
- package/dist/runtime/composables/useAvatarGroup.d.ts +1 -1
- package/dist/runtime/composables/useButtonGroup.d.ts +2 -2
- package/dist/runtime/composables/useFormItem.d.ts +2 -2
- package/dist/runtime/composables/useKbd.d.ts +1 -1
- package/dist/runtime/composables/useLocale.d.ts +3 -3
- package/dist/runtime/composables/useTheme.d.ts +1 -1
- package/dist/runtime/composables/useToast.d.ts +1 -1
- package/dist/runtime/locale/en.d.ts +1 -1
- package/dist/runtime/locale/zh-tw.d.ts +1 -1
- package/dist/runtime/theme/accordion.d.ts +45 -51
- package/dist/runtime/theme/accordion.js +1 -1
- package/dist/runtime/theme/alert.d.ts +115 -121
- package/dist/runtime/theme/alert.js +1 -1
- package/dist/runtime/theme/avatar-group.d.ts +42 -48
- package/dist/runtime/theme/avatar-group.js +1 -1
- package/dist/runtime/theme/avatar.d.ts +46 -52
- package/dist/runtime/theme/avatar.js +1 -1
- package/dist/runtime/theme/badge.d.ts +60 -66
- package/dist/runtime/theme/badge.js +1 -1
- package/dist/runtime/theme/breadcrumb.d.ts +52 -58
- package/dist/runtime/theme/breadcrumb.js +1 -1
- package/dist/runtime/theme/button-group.d.ts +36 -42
- package/dist/runtime/theme/button.d.ts +162 -168
- package/dist/runtime/theme/button.js +1 -1
- package/dist/runtime/theme/calendar.d.ts +52 -50
- package/dist/runtime/theme/calendar.js +20 -3
- package/dist/runtime/theme/card.d.ts +52 -58
- package/dist/runtime/theme/card.js +1 -1
- package/dist/runtime/theme/carousel.d.ts +98 -104
- package/dist/runtime/theme/carousel.js +1 -1
- package/dist/runtime/theme/checkbox.d.ts +77 -83
- package/dist/runtime/theme/checkbox.js +1 -1
- package/dist/runtime/theme/chip.d.ts +50 -56
- package/dist/runtime/theme/chip.js +1 -1
- package/dist/runtime/theme/collapsible.d.ts +29 -35
- package/dist/runtime/theme/collapsible.js +1 -1
- package/dist/runtime/theme/drawer.d.ts +120 -126
- package/dist/runtime/theme/drawer.js +1 -1
- package/dist/runtime/theme/dropdown-menu.d.ts +55 -61
- package/dist/runtime/theme/dropdown-menu.js +1 -1
- package/dist/runtime/theme/form-item.d.ts +63 -69
- package/dist/runtime/theme/form-item.js +1 -1
- package/dist/runtime/theme/form.d.ts +1 -7
- package/dist/runtime/theme/input-number.d.ts +98 -104
- package/dist/runtime/theme/input-number.js +1 -1
- package/dist/runtime/theme/input.d.ts +153 -159
- package/dist/runtime/theme/input.js +1 -1
- package/dist/runtime/theme/kbd.d.ts +30 -36
- package/dist/runtime/theme/link.d.ts +37 -43
- package/dist/runtime/theme/modal.d.ts +36 -42
- package/dist/runtime/theme/modal.js +1 -1
- package/dist/runtime/theme/pagination.d.ts +71 -77
- package/dist/runtime/theme/pagination.js +1 -1
- package/dist/runtime/theme/pinInput.d.ts +80 -86
- package/dist/runtime/theme/pinInput.js +1 -1
- package/dist/runtime/theme/popover.d.ts +29 -35
- package/dist/runtime/theme/popover.js +1 -1
- package/dist/runtime/theme/progress.d.ts +163 -169
- package/dist/runtime/theme/progress.js +1 -1
- package/dist/runtime/theme/radio-group.d.ts +99 -105
- package/dist/runtime/theme/radio-group.js +1 -1
- package/dist/runtime/theme/scroll-area.d.ts +62 -68
- package/dist/runtime/theme/scroll-area.js +1 -1
- package/dist/runtime/theme/select.d.ts +165 -171
- package/dist/runtime/theme/select.js +1 -1
- package/dist/runtime/theme/separator.d.ts +62 -68
- package/dist/runtime/theme/separator.js +1 -1
- package/dist/runtime/theme/skeleton.d.ts +1 -7
- package/dist/runtime/theme/slider.d.ts +62 -68
- package/dist/runtime/theme/slider.js +1 -1
- package/dist/runtime/theme/switch.d.ts +111 -117
- package/dist/runtime/theme/switch.js +1 -1
- package/dist/runtime/theme/table.d.ts +75 -81
- package/dist/runtime/theme/table.js +1 -1
- package/dist/runtime/theme/tabs.d.ts +114 -120
- package/dist/runtime/theme/tabs.js +1 -1
- package/dist/runtime/theme/textarea.d.ts +76 -82
- package/dist/runtime/theme/textarea.js +1 -1
- package/dist/runtime/theme/toast-provider.d.ts +106 -112
- package/dist/runtime/theme/toast-provider.js +1 -1
- package/dist/runtime/theme/toast.d.ts +74 -80
- package/dist/runtime/theme/toast.js +1 -1
- package/dist/runtime/theme/tooltip.d.ts +35 -41
- package/dist/runtime/theme/tooltip.js +1 -1
- package/dist/runtime/types/utils.d.ts +5 -5
- package/dist/runtime/utils/link.d.ts +3 -5
- package/dist/runtime/utils/styler.d.ts +2 -2
- package/dist/runtime/utils/styler.js +2 -2
- package/dist/shared/ui.D1BTWZFB.mjs +5 -0
- package/dist/shared/ui.D1BTWZFB.mjs.map +1 -0
- package/dist/types.d.mts +1 -1
- package/dist/unocss.mjs +5 -4
- package/dist/unocss.mjs.map +1 -1
- package/dist/unplugin.mjs +1 -1
- package/dist/unplugin.mjs.map +1 -1
- package/dist/vite.mjs +1 -1
- package/package.json +77 -75
- package/dist/module.cjs +0 -5
- package/dist/shared/ui.3e7fad19.mjs +0 -5
- package/dist/shared/ui.3e7fad19.mjs.map +0 -1
- package/dist/types.d.ts +0 -1
|
@@ -1,311 +1,197 @@
|
|
|
1
|
-
<script
|
|
2
|
-
import type { ComputedRef, DeepReadonly, Ref } from 'vue'
|
|
3
|
-
import type { form } from '../theme'
|
|
4
|
-
import type { ComponentAttrs, FormError, FormErrorEvent, FormErrorWithId, FormEvent, FormInputEvents, FormSchema, FormSubmitEvent, FormValidateOptions } from '../types'
|
|
5
|
-
|
|
6
|
-
export interface FormEmits<T extends object> {
|
|
7
|
-
submit: [payload: FormSubmitEvent<T>]
|
|
8
|
-
error: [payload: FormErrorEvent]
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface FormSlots {
|
|
12
|
-
default?: (props?: { errors: FormError[] }) => any
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface FormExpose<T extends object> {
|
|
16
|
-
validate: (options?: FormValidateOptions<T>) => Promise<T | false>
|
|
17
|
-
clear: (path?: string) => void
|
|
18
|
-
errors: Ref<FormError[]>
|
|
19
|
-
setErrors: (errors: FormError[], name?: keyof T) => void
|
|
20
|
-
getErrors: (name?: keyof T) => FormError[]
|
|
21
|
-
submit: () => Promise<void>
|
|
22
|
-
disabled: ComputedRef<boolean>
|
|
23
|
-
dirty: ComputedRef<boolean>
|
|
24
|
-
dirtyFields: DeepReadonly<Set<keyof T>>
|
|
25
|
-
touchedFields: DeepReadonly<Set<keyof T>>
|
|
26
|
-
blurredFields: DeepReadonly<Set<keyof T>>
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface FormProps<T extends object> extends Omit<ComponentAttrs<typeof form>, 'ui'> {
|
|
30
|
-
id?: string | number
|
|
31
|
-
/** Schema to validate the form state. */
|
|
32
|
-
schema?: FormSchema<T>
|
|
33
|
-
/** An object representing the current state of the form. */
|
|
34
|
-
state: Partial<T>
|
|
35
|
-
/**
|
|
36
|
-
* Custom validation function to validate the form state.
|
|
37
|
-
* @param state - The current state of the form.
|
|
38
|
-
* @returns A promise that resolves to an array of FormError objects, or an array of FormError objects directly.
|
|
39
|
-
*/
|
|
40
|
-
validate?: (state: Partial<T>) => Promise<FormError[]> | FormError[]
|
|
41
|
-
/**
|
|
42
|
-
* The list of input events that trigger the form validation.
|
|
43
|
-
* @default ["blur", "change", "input"]
|
|
44
|
-
*/
|
|
45
|
-
validateOn?: FormInputEvents[]
|
|
46
|
-
/** Disable all inputs inside the form. */
|
|
47
|
-
disabled?: boolean
|
|
48
|
-
/**
|
|
49
|
-
* Delay in milliseconds before validating the form on input events.
|
|
50
|
-
* @default 300
|
|
51
|
-
*/
|
|
52
|
-
validateOnInputDelay?: number
|
|
53
|
-
/**
|
|
54
|
-
* If true, schema transformations will be applied to the state on submit.
|
|
55
|
-
* @default true
|
|
56
|
-
*/
|
|
57
|
-
transform?: boolean
|
|
58
|
-
onSubmit?: ((event: FormSubmitEvent<T>) => void | Promise<void>) | (() => void | Promise<void>)
|
|
59
|
-
}
|
|
60
|
-
|
|
1
|
+
<script>
|
|
61
2
|
export class FormValidationExceptionError extends Error {
|
|
62
|
-
formId
|
|
63
|
-
errors
|
|
64
|
-
children
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
this.
|
|
69
|
-
this.
|
|
70
|
-
this.
|
|
71
|
-
this.
|
|
72
|
-
Object.setPrototypeOf(this, FormValidationExceptionError.prototype)
|
|
3
|
+
formId;
|
|
4
|
+
errors;
|
|
5
|
+
children;
|
|
6
|
+
constructor(formId, errors, childErrors) {
|
|
7
|
+
super("Form validation exception");
|
|
8
|
+
this.name = "FormValidationExceptionError";
|
|
9
|
+
this.formId = formId;
|
|
10
|
+
this.errors = errors;
|
|
11
|
+
this.children = childErrors;
|
|
12
|
+
Object.setPrototypeOf(this, FormValidationExceptionError.prototype);
|
|
73
13
|
}
|
|
74
14
|
}
|
|
75
15
|
</script>
|
|
76
16
|
|
|
77
|
-
<script setup
|
|
78
|
-
import { useEventBus } from
|
|
79
|
-
import { computed, nextTick, onMounted, onUnmounted, readonly, ref, useId } from
|
|
80
|
-
import { injectFormBus, provideFormBus, provideFormErrors, provideFormInputs, provideFormLoading, provideFormOptions } from
|
|
81
|
-
import { useTheme } from
|
|
82
|
-
import { validateSchema } from
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
17
|
+
<script setup>
|
|
18
|
+
import { useEventBus } from "@vueuse/core";
|
|
19
|
+
import { computed, nextTick, onMounted, onUnmounted, readonly, ref, useId } from "vue";
|
|
20
|
+
import { injectFormBus, provideFormBus, provideFormErrors, provideFormInputs, provideFormLoading, provideFormOptions } from "../app/injections";
|
|
21
|
+
import { useTheme } from "../composables/useTheme";
|
|
22
|
+
import { validateSchema } from "../utils";
|
|
23
|
+
const props = defineProps({
|
|
24
|
+
id: { type: [String, Number], required: false },
|
|
25
|
+
schema: { type: null, required: false },
|
|
26
|
+
state: { type: Object, required: true },
|
|
27
|
+
validate: { type: Function, required: false },
|
|
28
|
+
validateOn: { type: Array, required: false, default: () => ["input", "blur", "change"] },
|
|
29
|
+
disabled: { type: Boolean, required: false },
|
|
30
|
+
validateOnInputDelay: { type: Number, required: false, default: 300 },
|
|
31
|
+
transform: { type: Boolean, required: false, default: true },
|
|
32
|
+
onSubmit: { type: Function, required: false },
|
|
33
|
+
class: { type: null, required: false }
|
|
34
|
+
});
|
|
35
|
+
const emit = defineEmits(["submit", "error"]);
|
|
36
|
+
defineSlots();
|
|
37
|
+
const formId = props.id ?? useId();
|
|
38
|
+
const bus = useEventBus(`form-${formId}`);
|
|
39
|
+
const parentBus = injectFormBus();
|
|
40
|
+
provideFormBus(bus);
|
|
41
|
+
const nestedForms = ref(/* @__PURE__ */ new Map());
|
|
102
42
|
onMounted(() => {
|
|
103
43
|
bus.on(async (event) => {
|
|
104
|
-
if (event.type ===
|
|
105
|
-
nestedForms.value.set(event.formId, { validate: event.validate })
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if (event.type !== 'input')
|
|
112
|
-
await validateFn({ name: event.name, silent: true, nested: false })
|
|
44
|
+
if (event.type === "attach") {
|
|
45
|
+
nestedForms.value.set(event.formId, { validate: event.validate });
|
|
46
|
+
} else if (event.type === "detach") {
|
|
47
|
+
nestedForms.value.delete(event.formId);
|
|
48
|
+
} else if (props.validateOn?.includes(event.type) && !loading.value) {
|
|
49
|
+
if (event.type !== "input")
|
|
50
|
+
await validateFn({ name: event.name, silent: true, nested: false });
|
|
113
51
|
else if (event.eager || blurredFields.has(event.name))
|
|
114
|
-
await validateFn({ name: event.name, silent: true, nested: false })
|
|
52
|
+
await validateFn({ name: event.name, silent: true, nested: false });
|
|
115
53
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (event.type ===
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
dirtyFields.add(event.name)
|
|
125
|
-
})
|
|
126
|
-
})
|
|
127
|
-
|
|
54
|
+
if (event.type === "blur")
|
|
55
|
+
blurredFields.add(event.name);
|
|
56
|
+
if (event.type === "change" || event.type === "input" || event.type === "blur" || event.type === "focus")
|
|
57
|
+
touchedFields.add(event.name);
|
|
58
|
+
if (event.type === "change" || event.type === "input")
|
|
59
|
+
dirtyFields.add(event.name);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
128
62
|
onUnmounted(() => {
|
|
129
|
-
bus.reset()
|
|
130
|
-
})
|
|
131
|
-
|
|
63
|
+
bus.reset();
|
|
64
|
+
});
|
|
132
65
|
onMounted(async () => {
|
|
133
66
|
if (parentBus) {
|
|
134
|
-
await nextTick()
|
|
135
|
-
parentBus.emit({ type:
|
|
67
|
+
await nextTick();
|
|
68
|
+
parentBus.emit({ type: "attach", validate: validateFn, formId });
|
|
136
69
|
}
|
|
137
|
-
})
|
|
138
|
-
|
|
70
|
+
});
|
|
139
71
|
onUnmounted(() => {
|
|
140
72
|
if (parentBus)
|
|
141
|
-
parentBus.emit({ type:
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const touchedFields = new Set<keyof T>()
|
|
152
|
-
const blurredFields = new Set<keyof T>()
|
|
153
|
-
|
|
154
|
-
function resolveErrorIds(errs: FormError[]): FormErrorWithId[] {
|
|
73
|
+
parentBus.emit({ type: "detach", formId });
|
|
74
|
+
});
|
|
75
|
+
const errors = ref([]);
|
|
76
|
+
provideFormErrors(errors);
|
|
77
|
+
const inputs = ref({});
|
|
78
|
+
provideFormInputs(inputs);
|
|
79
|
+
const dirtyFields = /* @__PURE__ */ new Set();
|
|
80
|
+
const touchedFields = /* @__PURE__ */ new Set();
|
|
81
|
+
const blurredFields = /* @__PURE__ */ new Set();
|
|
82
|
+
function resolveErrorIds(errs) {
|
|
155
83
|
return errs.map((err) => ({
|
|
156
84
|
...err,
|
|
157
|
-
id: err?.name ? inputs.value[err.name]?.id :
|
|
158
|
-
}))
|
|
85
|
+
id: err?.name ? inputs.value[err.name]?.id : void 0
|
|
86
|
+
}));
|
|
159
87
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
async function getErrors(): Promise<FormErrorWithId[]> {
|
|
164
|
-
let errs = props.validate ? (await props.validate(props.state)) ?? [] : []
|
|
165
|
-
|
|
88
|
+
const transformedState = ref(null);
|
|
89
|
+
async function getErrors() {
|
|
90
|
+
let errs = props.validate ? await props.validate(props.state) ?? [] : [];
|
|
166
91
|
if (props.schema) {
|
|
167
|
-
const { errors, result } = await validateSchema(props.state, props.schema
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
errs = errs.concat(errors)
|
|
92
|
+
const { errors: errors2, result } = await validateSchema(props.state, props.schema);
|
|
93
|
+
if (errors2)
|
|
94
|
+
errs = errs.concat(errors2);
|
|
171
95
|
else
|
|
172
|
-
transformedState.value = result
|
|
96
|
+
transformedState.value = result;
|
|
173
97
|
}
|
|
174
|
-
|
|
175
|
-
return resolveErrorIds(errs)
|
|
98
|
+
return resolveErrorIds(errs);
|
|
176
99
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const _options: FormValidateOptions<T> = {
|
|
100
|
+
async function validateFn(options) {
|
|
101
|
+
const _options = {
|
|
180
102
|
silent: false,
|
|
181
103
|
nested: true,
|
|
182
104
|
transform: false,
|
|
183
|
-
...options
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
return error
|
|
195
|
-
}),
|
|
196
|
-
)
|
|
197
|
-
: []
|
|
198
|
-
|
|
105
|
+
...options
|
|
106
|
+
};
|
|
107
|
+
const names = _options.name && !Array.isArray(_options.name) ? [_options.name] : _options.name;
|
|
108
|
+
const nestedValidatePromises = !names && _options.nested ? Array.from(nestedForms.value.values()).map(
|
|
109
|
+
({ validate }) => validate(_options).then(() => {
|
|
110
|
+
}).catch((error) => {
|
|
111
|
+
if (!(error instanceof FormValidationExceptionError))
|
|
112
|
+
throw error;
|
|
113
|
+
return error;
|
|
114
|
+
})
|
|
115
|
+
) : [];
|
|
199
116
|
if (names) {
|
|
200
117
|
const otherErrors = errors.value.filter((error) => !names.some((name) => {
|
|
201
|
-
const pattern = inputs.value?.[name]?.pattern
|
|
202
|
-
return name === error.name ||
|
|
203
|
-
}))
|
|
204
|
-
|
|
205
|
-
// eslint-disable-next-line unicorn/no-await-expression-member
|
|
118
|
+
const pattern = inputs.value?.[name]?.pattern;
|
|
119
|
+
return name === error.name || pattern && error.name?.match(pattern);
|
|
120
|
+
}));
|
|
206
121
|
const pathErrors = (await getErrors()).filter((error) => names.some((name) => {
|
|
207
|
-
const pattern = inputs.value?.[name]?.pattern
|
|
208
|
-
return name === error.name ||
|
|
209
|
-
}))
|
|
210
|
-
|
|
211
|
-
|
|
122
|
+
const pattern = inputs.value?.[name]?.pattern;
|
|
123
|
+
return name === error.name || pattern && error.name?.match(pattern);
|
|
124
|
+
}));
|
|
125
|
+
errors.value = otherErrors.concat(pathErrors);
|
|
126
|
+
} else {
|
|
127
|
+
errors.value = await getErrors();
|
|
212
128
|
}
|
|
213
|
-
|
|
214
|
-
errors.value = await getErrors()
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// eslint-disable-next-line unicorn/no-await-expression-member
|
|
218
|
-
const childErrors = (await Promise.all(nestedValidatePromises)).filter((val) => val !== undefined)
|
|
219
|
-
|
|
129
|
+
const childErrors = (await Promise.all(nestedValidatePromises)).filter((val) => val !== void 0);
|
|
220
130
|
if (errors.value.length + childErrors.length > 0) {
|
|
221
131
|
if (_options.silent)
|
|
222
|
-
return false
|
|
223
|
-
|
|
224
|
-
throw new FormValidationExceptionError(formId, errors.value, childErrors)
|
|
132
|
+
return false;
|
|
133
|
+
throw new FormValidationExceptionError(formId, errors.value, childErrors);
|
|
225
134
|
}
|
|
226
|
-
|
|
227
135
|
if (_options.transform)
|
|
228
|
-
Object.assign(props.state, transformedState.value)
|
|
229
|
-
|
|
230
|
-
return props.state as T
|
|
136
|
+
Object.assign(props.state, transformedState.value);
|
|
137
|
+
return props.state;
|
|
231
138
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
loading.value = true
|
|
238
|
-
|
|
239
|
-
const event = payload as FormSubmitEvent<any>
|
|
240
|
-
|
|
139
|
+
const loading = ref(false);
|
|
140
|
+
provideFormLoading(readonly(loading));
|
|
141
|
+
async function onSubmitWrapper(payload) {
|
|
142
|
+
loading.value = true;
|
|
143
|
+
const event = payload;
|
|
241
144
|
try {
|
|
242
|
-
event.data = await validateFn({ nested: true, transform: props.transform })
|
|
243
|
-
await props.onSubmit?.(event)
|
|
244
|
-
dirtyFields.clear()
|
|
245
|
-
}
|
|
246
|
-
catch (error) {
|
|
145
|
+
event.data = await validateFn({ nested: true, transform: props.transform });
|
|
146
|
+
await props.onSubmit?.(event);
|
|
147
|
+
dirtyFields.clear();
|
|
148
|
+
} catch (error) {
|
|
247
149
|
if (!(error instanceof FormValidationExceptionError))
|
|
248
|
-
throw error
|
|
249
|
-
|
|
250
|
-
const errorEvent: FormErrorEvent = {
|
|
150
|
+
throw error;
|
|
151
|
+
const errorEvent = {
|
|
251
152
|
...event,
|
|
252
153
|
errors: error.errors,
|
|
253
|
-
children: error.children
|
|
254
|
-
}
|
|
255
|
-
emit(
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
loading.value = false
|
|
154
|
+
children: error.children
|
|
155
|
+
};
|
|
156
|
+
emit("error", errorEvent);
|
|
157
|
+
} finally {
|
|
158
|
+
loading.value = false;
|
|
259
159
|
}
|
|
260
160
|
}
|
|
261
|
-
|
|
262
|
-
const disabled = computed(() => props.disabled || loading.value)
|
|
263
|
-
|
|
161
|
+
const disabled = computed(() => props.disabled || loading.value);
|
|
264
162
|
provideFormOptions(computed(() => ({
|
|
265
163
|
disabled: disabled.value,
|
|
266
|
-
validateOnInputDelay: props.validateOnInputDelay
|
|
267
|
-
})))
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
validate: validateFn as FormExpose<T>['validate'],
|
|
164
|
+
validateOnInputDelay: props.validateOnInputDelay
|
|
165
|
+
})));
|
|
166
|
+
defineExpose({
|
|
167
|
+
validate: validateFn,
|
|
271
168
|
errors,
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
errors.value = name
|
|
275
|
-
? errors.value
|
|
276
|
-
.filter((error) => error.name !== name)
|
|
277
|
-
.concat(resolveErrorIds(errs))
|
|
278
|
-
: resolveErrorIds(errs)
|
|
169
|
+
setErrors(errs, name) {
|
|
170
|
+
errors.value = name ? errors.value.filter((error) => error.name !== name).concat(resolveErrorIds(errs)) : resolveErrorIds(errs);
|
|
279
171
|
},
|
|
280
|
-
|
|
281
172
|
async submit() {
|
|
282
|
-
await onSubmitWrapper(new Event(
|
|
173
|
+
await onSubmitWrapper(new Event("submit"));
|
|
283
174
|
},
|
|
284
|
-
|
|
285
|
-
getErrors(name?: keyof T) {
|
|
175
|
+
getErrors(name) {
|
|
286
176
|
if (name)
|
|
287
|
-
return errors.value.filter((err) => err.name === name)
|
|
288
|
-
|
|
289
|
-
return errors.value
|
|
177
|
+
return errors.value.filter((err) => err.name === name);
|
|
178
|
+
return errors.value;
|
|
290
179
|
},
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
errors.value = name ? errors.value.filter((err) => err.name !== name) : []
|
|
180
|
+
clear(name) {
|
|
181
|
+
errors.value = name ? errors.value.filter((err) => err.name !== name) : [];
|
|
294
182
|
},
|
|
295
|
-
|
|
296
183
|
disabled,
|
|
297
184
|
dirty: computed(() => dirtyFields.size > 0),
|
|
298
|
-
dirtyFields: readonly(dirtyFields)
|
|
299
|
-
blurredFields: readonly(blurredFields)
|
|
300
|
-
touchedFields: readonly(touchedFields)
|
|
301
|
-
})
|
|
302
|
-
|
|
303
|
-
const
|
|
304
|
-
const style = computed(() => generateStyle('form', props))
|
|
185
|
+
dirtyFields: readonly(dirtyFields),
|
|
186
|
+
blurredFields: readonly(blurredFields),
|
|
187
|
+
touchedFields: readonly(touchedFields)
|
|
188
|
+
});
|
|
189
|
+
const { generateStyle } = useTheme();
|
|
190
|
+
const style = computed(() => generateStyle("form", props));
|
|
305
191
|
</script>
|
|
306
192
|
|
|
307
193
|
<template>
|
|
308
|
-
<component :is="parentBus ? 'div' : 'form'" :id="formId" :class="style" @submit.prevent="onSubmitWrapper">
|
|
194
|
+
<component :is="parentBus ? 'div' : 'form'" :id="formId" :class="style.base()" data-part="base" @submit.prevent="onSubmitWrapper">
|
|
309
195
|
<slot :errors="errors"></slot>
|
|
310
196
|
</component>
|
|
311
197
|
</template>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { ComputedRef, DeepReadonly, Ref } from 'vue';
|
|
2
|
+
import type { form } from '../theme/index.js';
|
|
3
|
+
import type { ComponentAttrs, FormError, FormErrorEvent, FormErrorWithId, FormInputEvents, FormSchema, FormSubmitEvent, FormValidateOptions } from '../types/index.js';
|
|
4
|
+
export interface FormEmits<T extends object> {
|
|
5
|
+
submit: [payload: FormSubmitEvent<T>];
|
|
6
|
+
error: [payload: FormErrorEvent];
|
|
7
|
+
}
|
|
8
|
+
export interface FormSlots {
|
|
9
|
+
default?: (props?: {
|
|
10
|
+
errors: FormError[];
|
|
11
|
+
}) => any;
|
|
12
|
+
}
|
|
13
|
+
export interface FormExpose<T extends object> {
|
|
14
|
+
validate: (options?: FormValidateOptions<T>) => Promise<T | false>;
|
|
15
|
+
clear: (path?: string) => void;
|
|
16
|
+
errors: Ref<FormError[]>;
|
|
17
|
+
setErrors: (errors: FormError[], name?: keyof T) => void;
|
|
18
|
+
getErrors: (name?: keyof T) => FormError[];
|
|
19
|
+
submit: () => Promise<void>;
|
|
20
|
+
disabled: ComputedRef<boolean>;
|
|
21
|
+
dirty: ComputedRef<boolean>;
|
|
22
|
+
dirtyFields: DeepReadonly<Set<keyof T>>;
|
|
23
|
+
touchedFields: DeepReadonly<Set<keyof T>>;
|
|
24
|
+
blurredFields: DeepReadonly<Set<keyof T>>;
|
|
25
|
+
}
|
|
26
|
+
export interface FormProps<T extends object> extends Omit<ComponentAttrs<typeof form>, 'ui'> {
|
|
27
|
+
id?: string | number;
|
|
28
|
+
/** Schema to validate the form state. */
|
|
29
|
+
schema?: FormSchema<T>;
|
|
30
|
+
/** An object representing the current state of the form. */
|
|
31
|
+
state: Partial<T>;
|
|
32
|
+
/**
|
|
33
|
+
* Custom validation function to validate the form state.
|
|
34
|
+
* @param state - The current state of the form.
|
|
35
|
+
* @returns A promise that resolves to an array of FormError objects, or an array of FormError objects directly.
|
|
36
|
+
*/
|
|
37
|
+
validate?: (state: Partial<T>) => Promise<FormError[]> | FormError[];
|
|
38
|
+
/**
|
|
39
|
+
* The list of input events that trigger the form validation.
|
|
40
|
+
* @default ["blur", "change", "input"]
|
|
41
|
+
*/
|
|
42
|
+
validateOn?: FormInputEvents[];
|
|
43
|
+
/** Disable all inputs inside the form. */
|
|
44
|
+
disabled?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Delay in milliseconds before validating the form on input events.
|
|
47
|
+
* @default 300
|
|
48
|
+
*/
|
|
49
|
+
validateOnInputDelay?: number;
|
|
50
|
+
/**
|
|
51
|
+
* If true, schema transformations will be applied to the state on submit.
|
|
52
|
+
* @default true
|
|
53
|
+
*/
|
|
54
|
+
transform?: boolean;
|
|
55
|
+
onSubmit?: ((event: FormSubmitEvent<T>) => void | Promise<void>) | (() => void | Promise<void>);
|
|
56
|
+
}
|
|
57
|
+
export declare class FormValidationExceptionError extends Error {
|
|
58
|
+
formId: string | number;
|
|
59
|
+
errors: FormErrorWithId[];
|
|
60
|
+
children?: FormValidationExceptionError[];
|
|
61
|
+
constructor(formId: string | number, errors: FormErrorWithId[], childErrors?: FormValidationExceptionError[]);
|
|
62
|
+
}
|
|
63
|
+
declare const _default: <T extends object>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
64
|
+
props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{
|
|
65
|
+
readonly onError?: ((payload: FormErrorEvent) => any) | undefined;
|
|
66
|
+
readonly onSubmit?: ((payload: FormSubmitEvent<T>) => any) | undefined;
|
|
67
|
+
} & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, never>, "onSubmit" | "onError"> & FormProps<T> & Partial<{}>> & import("vue").PublicProps;
|
|
68
|
+
expose(exposed: import("vue").ShallowUnwrapRef<FormExpose<T>>): void;
|
|
69
|
+
attrs: any;
|
|
70
|
+
slots: FormSlots;
|
|
71
|
+
emit: ((evt: "error", payload: FormErrorEvent) => void) & ((evt: "submit", payload: FormSubmitEvent<T>) => void);
|
|
72
|
+
}>) => import("vue").VNode & {
|
|
73
|
+
__ctx?: Awaited<typeof __VLS_setup>;
|
|
74
|
+
};
|
|
75
|
+
export default _default;
|
|
76
|
+
type __VLS_PrettifyLocal<T> = {
|
|
77
|
+
[K in keyof T]: T[K];
|
|
78
|
+
} & {};
|