Skip to content

Commit

Permalink
feat(validation): add computed option to useForm
Browse files Browse the repository at this point in the history
  • Loading branch information
kiaking committed Mar 9, 2023
1 parent a7876af commit 1bdcbd1
Showing 1 changed file with 47 additions and 14 deletions.
61 changes: 47 additions & 14 deletions lib/composables/Form.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import type { Ref } from 'vue'
import { computed } from 'vue'
import { type Ref, computed, reactive, toRefs } from 'vue'
import { useSnackbars } from '../stores/Snackbars'
import type { UseDataInput } from './Data'
import { useData } from './Data'
import type { Validation } from './Validation'
import { useValidation } from './Validation'
import { type UseDataInput, useData } from './Data'
import { type Validation, useValidation } from './Validation'

export interface Form<T extends Record<string, any>> {
data: T
Expand All @@ -15,25 +12,49 @@ export interface Form<T extends Record<string, any>> {
validateAndNotify(): Promise<boolean>
}

export interface UseFormOptions<T extends Record<string, any>> {
data: UseDataInput<T>
rules?: Record<string, any> | ((state: T) => Record<string, any>)
export type ComputedData<T extends Record<string, () => any>> = {
[K in keyof T]: ReturnType<T[K]>
}

export type AllData<
D extends Record<string, any>,
C extends Record<string, () => any>
> = D & ComputedData<C>

export interface UseFormOptions<
D extends Record<string, any>,
C extends Record<string, () => any>
> {
data: UseDataInput<D>
computed?: (data: D) => C
rules?: Record<string, any> | ((data: AllData<D, C>) => Record<string, any>)
}

export function useForm<
T extends Record<string, any>
>(options: UseFormOptions<T>): Form<T> {
D extends Record<string, any> = Record<string, any>,
C extends Record<string, () => any> = Record<string, () => any>
>(options: UseFormOptions<D, C>): Form<AllData<D, C>> {
const snackbars = useSnackbars()

const data = useData(options.data)
const dataStateRef = toRefs(data.state)

const computedData = options.computed
? createComputedData(options.computed(data.state))
: {}

const allData = reactive({
...dataStateRef,
...computedData
}) as AllData<D, C>

const rules = computed(() => {
return options.rules
? typeof options.rules === 'function' ? options.rules(data.state) : options.rules
? typeof options.rules === 'function' ? options.rules(allData) : options.rules
: {}
})

const validation = useValidation(data.state, rules)
const validation = useValidation(allData, rules)

function init(): void {
data.init()
Expand Down Expand Up @@ -62,11 +83,23 @@ export function useForm<
}

return {
data: data.state,
data: allData,
init,
reset,
validation,
validate,
validateAndNotify
}
}

function createComputedData<
C extends Record<string, () => any>
>(input: C): ComputedData<C> {
const computedData = {} as any

for (const [key, fn] of Object.entries(input)) {
computedData[key] = computed(() => fn())
}

return computedData
}

0 comments on commit 1bdcbd1

Please sign in to comment.