diff --git a/packages/form/package.json b/packages/form/package.json index 5fc1aed..4737096 100644 --- a/packages/form/package.json +++ b/packages/form/package.json @@ -1,7 +1,7 @@ { "name": "schemastery-vue", "description": "Type driven schema validator", - "version": "7.0.1", + "version": "7.0.3", "main": "src/index.ts", "repository": { "type": "git", diff --git a/packages/form/src/extensions/union.vue b/packages/form/src/extensions/union.vue index 92283fb..cda3566 100644 --- a/packages/form/src/extensions/union.vue +++ b/packages/form/src/extensions/union.vue @@ -44,7 +44,7 @@ import { computed, PropType, ref, watch, WatchStopHandle } from 'vue' import { deepEqual, isNullable } from 'cosmokit' import { useI18n } from 'vue-i18n' -import { check, getChoices, getFallback, Schema, useI18nText } from '../utils' +import { check, getChoices, getFallback, Schema, useModel, useI18nText } from '../utils' import zhCN from '../locales/zh-CN.yml' import enUS from '../locales/en-US.yml' @@ -57,21 +57,13 @@ const props = defineProps({ extra: {} as PropType, }) -const emit = defineEmits(['update:modelValue']) +defineEmits(['update:modelValue']) const tt = useI18nText() -const config = ref() const choices = ref() const cache = ref() const active = ref() -let stop: WatchStopHandle - -const doWatch = () => watch(config, (value) => { - const index = choices.value.indexOf(active.value) - if (index >= 0) cache.value[index] = value - emit('update:modelValue', deepEqual(value, props.schema.meta.default) ? null : value) -}, { deep: true }) watch(() => props.schema, (value) => { choices.value = getChoices(props.schema) @@ -81,36 +73,35 @@ watch(() => props.schema, (value) => { }) }, { immediate: true }) -watch(() => [props.modelValue, props.schema] as const, ([value, schema]) => { - stop?.() - config.value = value - value ??= schema.meta.default - active.value = null - let hasTransform = true, depth = 0 - while (!active.value && hasTransform && ++depth < 10) { - hasTransform = false - for (const item of schema.list) { - if (item.meta.hidden) continue - if (!check(item, value)) continue - if (item.type === 'transform') { - if (!item.callback) continue - try { - value = item.callback(value) - } catch (error) { - console.error(error) - continue +const config = useModel({ + input(value) { + active.value = null + let hasTransform = true, depth = 0 + while (!active.value && hasTransform && ++depth < 10) { + hasTransform = false + for (const [index, item] of props.schema.list.entries()) { + if (item.meta.hidden) continue + if (!check(item, value)) continue + if (item.type === 'transform') { + if (!item.callback) continue + try { + value = item.callback(value) + } catch (error) { + console.error(error) + continue + } + hasTransform = true + value ??= getFallback(props.schema) + } else { + active.value = item + cache.value[index] = value } - hasTransform = true - config.value = value - value ??= schema.meta.default - } else { - active.value = item + break } - break } - } - stop = doWatch() -}, { immediate: true, deep: true }) + return value + }, +}) const selectModel = computed({ get() { diff --git a/packages/form/src/utils.ts b/packages/form/src/utils.ts index b3bae40..a077ace 100644 --- a/packages/form/src/utils.ts +++ b/packages/form/src/utils.ts @@ -90,8 +90,8 @@ export function useDisabled() { interface ConfigOptions { strict?: boolean - input(value: any): T - output(value: T): any + input?(value: any): T + output?(value: T): any } export function useModel(options?: ConfigOptions) { @@ -101,7 +101,7 @@ export function useModel(options?: ConfigOptions) { const doWatch = () => watch(config, (value) => { try { - if (options) value = options.output(value) + if (options?.output) value = options.output(value) } catch { return } @@ -109,13 +109,13 @@ export function useModel(options?: ConfigOptions) { emit('update:modelValue', value) }, { deep: true }) - watch([() => props.modelValue, () => props.schema], ([value, schema]) => { + watch(() => [props.modelValue, props.schema], ([value, schema]) => { stop?.() value ??= getFallback(schema) - if (options) value = options.input(value) + if (options?.input) value = options.input(value) config.value = value stop = doWatch() - }, { immediate: true }) + }, { deep: true, immediate: true }) return config }