From 0ee61a86a81743ba89f5259763c4975e766b0ad6 Mon Sep 17 00:00:00 2001 From: Nozomu Ikuta <16436160+NozomuIkuta@users.noreply.github.com> Date: Tue, 9 Jan 2024 01:12:15 +0900 Subject: [PATCH] feat: add `useV7dObject` composable --- .../vue-v8n/src/composables/useV7dObject.ts | 173 ++++++++++++++++++ packages/vue-v8n/src/index.ts | 1 + playground/src/App.vue | 1 + playground/src/components/DemoView.vue | 40 ++-- playground/src/pages/NumberDemo.vue | 34 +++- playground/src/pages/ObjectDemo.vue | 94 ++++++++++ playground/src/pages/PasswordDemo.vue | 34 +++- playground/src/pages/StringDemo.vue | 34 +++- playground/src/router.ts | 2 + playground/src/utils.ts | 23 --- 10 files changed, 378 insertions(+), 58 deletions(-) create mode 100644 packages/vue-v8n/src/composables/useV7dObject.ts create mode 100644 playground/src/pages/ObjectDemo.vue delete mode 100644 playground/src/utils.ts diff --git a/packages/vue-v8n/src/composables/useV7dObject.ts b/packages/vue-v8n/src/composables/useV7dObject.ts new file mode 100644 index 0000000..f572540 --- /dev/null +++ b/packages/vue-v8n/src/composables/useV7dObject.ts @@ -0,0 +1,173 @@ +import { computed, reactive } from 'vue' +import type { MaybeRefOrGetter, UnwrapRef } from 'vue' +import type { RuleDefinition, UseV7dOptions } from '../types' +import { useV7d } from './useV7d' + +export function useV7dObject>( + values: T, + rules: Partial>>, + options?: Partial> +) { + type InitialValues = Record + type Values = Record>['value']['value']> + + const _initialValues = {} as InitialValues + const _values = reactive({} as Values) + const $els = {} as Record>['$el']> + const _touched = {} as Record>['$touched']> + const _error = {} as Record>['$error']> + const _errors = {} as Record>['$errors']> + const _touchFns = {} as Record>['$touch']> + const _validateFns = {} as Record>['$validate']> + const _resetFns = {} as Record>['$reset']> + const _resetWithInitialValueFns = {} as Record>['$resetWithInitialValue']> + const _resetWithFn = {} as Record>['$resetWith']> + + const _keys = Object.keys(values) + + for (const key of _keys) { + const _key = key as keyof T + const { + value, + $el, + $touched, + $error, + $errors, + $touch, + $validate, + $reset, + $resetWithInitialValue, + $resetWith + } = useV7d(values[_key], rules[_key] ?? [], options?.[_key] ?? {}) + + _initialValues[_key] = values[_key] + ;(_values as Values)[_key] = value.value + $els[_key] = $el + _touched[_key] = $touched + _error[_key] = $error + _errors[_key] = $errors + _touchFns[_key] = $touch + _validateFns[_key] = $validate + _resetFns[_key] = $reset + _resetWithInitialValueFns[_key] = $resetWithInitialValue + _resetWithFn[_key] = $resetWith + } + + const $touchedAny = computed(() => { + for (const key of _keys) { + const _key = key as keyof T + + if (_touched[_key].value) { + return true + } + } + + return false + }) + + const $touched = computed(() => { + const _$touched = {} as Record>['$touched']['value']> + + for (const key of _keys) { + const _key = key as keyof T + _$touched[_key] = _touched[_key].value + } + + return _$touched + }) + + const $error = computed(() => { + const _$error = {} as Record>['$error']['value']> + + for (const key of _keys) { + const _key = key as keyof T + _$error[_key] = _error[_key].value + } + + return _$error + }) + + const $errors = computed(() => { + const _$errors = {} as Record>['$errors']['value']> + + for (const key of _keys) { + const _key = key as keyof T + _$errors[_key] = _errors[_key as keyof T].value + } + + return _$errors + }) + + function $touch(key?: keyof T) { + if (typeof key === 'string') { + _touchFns[key]() + return + } + + for (const key of _keys) { + const _key = key as keyof T + _touchFns[_key]() + } + } + + function $validate(key?: keyof T) { + if (typeof key === 'string') { + return _validateFns[key]() + } + + const results = {} as Record>['$validate']>> + + for (const key of _keys) { + const _key = key as keyof T + results[_key] = _validateFns[_key]() + } + + return results + } + + function $reset(key?: keyof T) { + if (typeof key === 'string') { + _resetFns[key]() + return + } + + for (const key of _keys) { + const _key = key as keyof T + _resetFns[_key]() + } + } + + function $resetWithInitialValue(key?: keyof T) { + if (typeof key === 'string') { + $reset(key) + ;(_values as any)[key] = _initialValues[key] + return + } + + $reset() + + for (const key of _keys) { + const _key = key as keyof T + ;(_values as any)[_key] = _initialValues[_key] + } + } + + function $resetWith(key: keyof T, newValue: UnwrapRef) { + $reset(key) + ;(_values as Values)[key] = newValue + } + + return { + values: _values, + $els, + $touchedAny, + $touched, + $error, + $errors, + $touch, + $validate, + $reset, + $resetWithInitialValue, + $resetWith + } +} diff --git a/packages/vue-v8n/src/index.ts b/packages/vue-v8n/src/index.ts index b5cb89b..12fdf9d 100644 --- a/packages/vue-v8n/src/index.ts +++ b/packages/vue-v8n/src/index.ts @@ -1,4 +1,5 @@ export { useV7d } from './composables/useV7d' +export { useV7dObject } from './composables/useV7dObject' export { max } from './rules/max' export { min } from './rules/min' export { required } from './rules/required' diff --git a/playground/src/App.vue b/playground/src/App.vue index 71f6b27..1235092 100644 --- a/playground/src/App.vue +++ b/playground/src/App.vue @@ -4,6 +4,7 @@ import { RouterLink } from 'vue-router' const menuItems = computed(() => [ { label: 'Number', to: '/number' }, + { label: 'Object', to: '/object' }, { label: 'Password', to: '/password' }, { label: 'String', to: '/string' } ]) diff --git a/playground/src/components/DemoView.vue b/playground/src/components/DemoView.vue index dad4721..da83acb 100644 --- a/playground/src/components/DemoView.vue +++ b/playground/src/components/DemoView.vue @@ -1,11 +1,21 @@