Skip to content

Commit

Permalink
fix: fix edge cases
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed May 1, 2023
1 parent 5d0a168 commit 764296a
Show file tree
Hide file tree
Showing 13 changed files with 65 additions and 35 deletions.
2 changes: 1 addition & 1 deletion packages/form/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "schemastery-vue",
"description": "Type driven schema validator",
"version": "4.0.0-alpha.4",
"version": "4.0.0-alpha.5",
"main": "src/index.ts",
"repository": {
"type": "git",
Expand Down
6 changes: 1 addition & 5 deletions packages/form/src/base.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ defineProps({
disabled: {} as PropType<boolean>,
prefix: {} as PropType<string>,
initial: {} as PropType<{}>,
foldable: Boolean,
extra: {} as PropType<any>,
})
defineEmits(['update:modelValue', 'visible-change'])
Expand All @@ -69,10 +69,6 @@ defineEmits(['update:modelValue', 'visible-change'])
}
}
.el-button.ellipsis {
padding: 8px 10px;
}
.el-button + .el-button {
margin-left: 0;
}
Expand Down
1 change: 0 additions & 1 deletion packages/form/src/extensions/bitset.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ defineProps({
disabled: {} as PropType<boolean>,
prefix: {} as PropType<string>,
initial: {} as PropType<{}>,
foldable: Boolean,
})
defineEmits(['update:modelValue'])
Expand Down
17 changes: 10 additions & 7 deletions packages/form/src/extensions/group.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<template #prefix><slot name="prefix"></slot></template>
<template #suffix><slot name="suffix"></slot></template>
<template #control>
<el-button type="primary" @click="add()" :disabled="disabled">添加项</el-button>
<el-button type="primary" @click="add()" :disabled="disabled">添加项目</el-button>
</template>
</schema-base>

Expand All @@ -15,17 +15,20 @@
v-for="([key, _], index) in entries"
:key="index"
v-model="entries[index][1]"
:invalid="entries.filter(e => e[0] === key).length > 1"
:initial="(initial ?? schema.meta.default)[key]"
:schema="schema.inner"
:disabled="disabled"
:prefix="schema.type === 'array' ? `${prefix.slice(0, -1)}[${key}].` : prefix + key + '.'"
foldable
:extra="{
foldable: true,
changed: key in (initial ?? schema.meta.default) ? undefined : true,
invalid: entries.filter(e => e[0] === key).length > 1,
}"
>
<template #menu>
<el-dropdown-item divided :disabled="!index" @click="up(index)">上移</el-dropdown-item>
<el-dropdown-item :disabled="index === entries.length - 1" @click="down(index)">下移</el-dropdown-item>
<el-dropdown-item @click="del(index)">删除</el-dropdown-item>
<el-dropdown-item divided :disabled="!index" @click="up(index)">上移项目</el-dropdown-item>
<el-dropdown-item :disabled="index === entries.length - 1" @click="down(index)">下移项目</el-dropdown-item>
<el-dropdown-item @click="del(index)">删除项目</el-dropdown-item>
</template>
<template #title>
<span class="prefix">{{ prefix.slice(0, -1) }}</span>
Expand Down Expand Up @@ -56,7 +59,7 @@ defineProps({
disabled: {} as PropType<boolean>,
prefix: {} as PropType<string>,
initial: {} as PropType<any>,
foldable: Boolean,
extra: {} as PropType<any>,
})
defineEmits(['update:modelValue'])
Expand Down
11 changes: 9 additions & 2 deletions packages/form/src/extensions/intersect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@
</k-schema>
</template>

<script lang="ts">
export default {
inheritAttrs: false,
}
</script>

<script lang="ts" setup>
import { PropType } from 'vue'
Expand All @@ -26,8 +34,7 @@ defineProps({
disabled: {} as PropType<boolean>,
prefix: {} as PropType<string>,
initial: {} as PropType<any>,
class: {} as PropType<any>,
foldable: Boolean,
extra: {} as PropType<any>,
})
defineEmits(['update:modelValue'])
Expand Down
19 changes: 15 additions & 4 deletions packages/form/src/extensions/object.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
<template>
<schema-base v-if="foldable">
<schema-base v-if="extra?.foldable" v-bind="$attrs">
<template #title><slot name="title"></slot></template>
<template #desc>
<k-markdown :source="schema.meta.description"></k-markdown>
<slot name="desc">
<k-markdown :source="schema?.meta.description"></k-markdown>
</slot>
</template>
<template #menu><slot name="menu"></slot></template>
<template #prefix><slot name="prefix"></slot></template>
<template #suffix><slot name="suffix"></slot></template>
</schema-base>
<h2 class="k-schema-header" v-else-if="schema.meta.description">
{{ schema.meta.description }}
Expand All @@ -25,6 +29,14 @@
</k-schema>
</template>

<script lang="ts">
export default {
inheritAttrs: false,
}
</script>

<script lang="ts" setup>
import { PropType } from 'vue'
Expand All @@ -37,8 +49,7 @@ defineProps({
disabled: {} as PropType<boolean>,
prefix: {} as PropType<string>,
initial: {} as PropType<any>,
foldable: Boolean,
class: {} as PropType<any>,
extra: {} as PropType<any>,
})
defineEmits(['update:modelValue'])
Expand Down
1 change: 0 additions & 1 deletion packages/form/src/extensions/radio.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ defineProps({
disabled: {} as PropType<boolean>,
prefix: {} as PropType<string>,
initial: {} as PropType<{}>,
foldable: Boolean,
})
defineEmits(['update:modelValue'])
Expand Down
1 change: 0 additions & 1 deletion packages/form/src/extensions/table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ defineProps({
disabled: {} as PropType<boolean>,
prefix: {} as PropType<string>,
initial: {} as PropType<{}>,
foldable: Boolean,
})
defineEmits(['update:modelValue'])
Expand Down
1 change: 0 additions & 1 deletion packages/form/src/extensions/textarea.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ const props = defineProps({
disabled: {} as PropType<boolean>,
prefix: {} as PropType<string>,
initial: {} as PropType<{}>,
foldable: Boolean,
})
defineEmits(['update:modelValue'])
Expand Down
1 change: 0 additions & 1 deletion packages/form/src/extensions/tuple.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ const props = defineProps({
disabled: {} as PropType<boolean>,
prefix: {} as PropType<string>,
initial: {} as PropType<{}>,
foldable: Boolean,
})
const emit = defineEmits(['update:modelValue'])
Expand Down
7 changes: 4 additions & 3 deletions packages/form/src/extensions/union.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
:disabled="disabled"
:prefix="prefix"
:extra="{
foldable: !!prefix,
required: !!schema.meta.required && isNullable(schema.meta.default) && isNullable(modelValue),
}"
>
Expand All @@ -15,6 +16,7 @@
</template>
<template #prefix>
<el-select
v-if="choices.length > 1"
v-model="selectModel"
filterable
:disabled="disabled"
Expand Down Expand Up @@ -42,8 +44,7 @@ const props = defineProps({
disabled: {} as PropType<boolean>,
prefix: {} as PropType<string>,
initial: {} as PropType<any>,
class: {} as PropType<any>,
foldable: Boolean,
extra: {} as PropType<any>,
})
const emit = defineEmits(['update:modelValue'])
Expand All @@ -57,7 +58,7 @@ 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) ? undefined : value)
emit('update:modelValue', deepEqual(value, props.schema.meta.default) ? null : value)
}, { deep: true })
watch(() => props.schema, (value) => {
Expand Down
10 changes: 10 additions & 0 deletions packages/form/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace form {
export interface Extension {
type: string
role?: string
validate?: (value: any, schema: any) => boolean
component: Component
}

Expand All @@ -29,26 +30,31 @@ namespace form {
extensions.add({
type: 'bitset',
component: Bitset,
validate: value => typeof value === 'number',
})

extensions.add({
type: 'array',
component: Group,
validate: value => Array.isArray(value),
})

extensions.add({
type: 'dict',
component: Group,
validate: value => typeof value === 'object',
})

extensions.add({
type: 'object',
component: Object,
validate: value => typeof value === 'object',
})

extensions.add({
type: 'intersect',
component: Intersect,
validate: value => typeof value === 'object',
})

extensions.add({
Expand All @@ -61,23 +67,27 @@ namespace form {
type: 'array',
role: 'table',
component: Table,
validate: value => Array.isArray(value),
})

extensions.add({
type: 'dict',
role: 'table',
component: Table,
validate: value => typeof value === 'object',
})

extensions.add({
type: 'string',
role: 'textarea',
component: Textarea,
validate: value => typeof value === 'string',
})

extensions.add({
type: 'tuple',
component: Tuple,
validate: value => Array.isArray(value),
})

extensions.add({
Expand Down
23 changes: 15 additions & 8 deletions packages/form/src/schema.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
<template>
<schema-component
v-if="!schema?.meta.hidden"
v-if="!schema?.meta.hidden && (extra?.foldable || (schema && schema.type !== 'const'))"
:schema="schema"
:prefix="prefix"
:initial="initial"
:disabled="disabled"
:foldable="foldable"
:extra="extra"
:modelValue="modelValue"
@update:modelValue="$emit('update:modelValue', $event)"
:class="{
changed: !deepEqual(initial, modelValue),
changed: extra?.changed ?? !deepEqual(initial, modelValue),
required: extra?.required ?? (schema?.meta.required && isNullable(schema?.meta.default) && isNullable(modelValue)),
invalid,
invalid: extra?.invalid,
}"
>
<template #title><slot name="title"></slot></template>
Expand All @@ -28,7 +28,7 @@
<template #prefix><slot name="prefix"></slot></template>
<template #suffix><slot name="suffix"></slot></template>
<template #control>
<schema-primitive v-if="['string', 'number', 'boolean'].includes(schema?.type)"
<schema-primitive v-if="isPrimitive"
:schema="schema"
:disabled="disabled"
:modelValue="modelValue"
Expand All @@ -49,21 +49,28 @@ import SchemaBase from './base.vue'
const props = defineProps({
schema: {} as PropType<Schema>,
initial: {} as PropType<any>,
modelValue: {},
invalid: Boolean,
modelValue: {} as PropType<any>,
extra: {} as PropType<any>,
disabled: Boolean,
foldable: Boolean,
branch: Boolean,
prefix: { type: String, default: '' },
})
defineEmits(['update:modelValue'])
const isPrimitive = computed(() => {
return ['string', 'number', 'boolean'].includes(props.schema?.type)
&& (isNullable(props.modelValue) || typeof props.modelValue === props.schema.type)
})
const SchemaComponent = computed(() => {
const candidates = [...form.extensions].map((ext) => {
if (ext.type && props.schema?.type !== ext.type) return
if (ext.role && props.schema?.meta.role !== ext.role) return
if (ext.validate) {
const valid = isNullable(props.modelValue) || ext.validate(props.modelValue, props.schema)
if (!valid) return
}
return [ext.component, +!!ext.type + +!!ext.role] as const
}).filter(Boolean).sort((a, b) => b[1] - a[1])
candidates.push([SchemaBase, 0])
Expand Down

0 comments on commit 764296a

Please sign in to comment.