in packages/vue/src/components/RecursionField.ts [45:196]
setup(props: IRecursionFieldProps) {
const parentRef = useField()
const optionsRef = inject(SchemaOptionsSymbol)
const scopeRef = inject(SchemaExpressionScopeSymbol)
const createSchema = (schemaProp: IRecursionFieldProps['schema']) =>
markRaw(new Schema(schemaProp))
const fieldSchemaRef = computed(() => createSchema(props.schema))
const getPropsFromSchema = (schema: Schema) =>
schema?.toFieldProps?.({
...optionsRef.value,
get scope() {
return lazyMerge(optionsRef.value.scope, scopeRef.value)
},
})
const fieldPropsRef = shallowRef(getPropsFromSchema(fieldSchemaRef.value))
watch([fieldSchemaRef, optionsRef], () => {
fieldPropsRef.value = getPropsFromSchema(fieldSchemaRef.value)
})
const getBasePath = () => {
if (props.onlyRenderProperties) {
return props.basePath ?? parentRef?.value?.address.concat(props.name)
}
return props.basePath ?? parentRef?.value?.address
}
provide(SchemaSymbol, fieldSchemaRef)
return () => {
const basePath = getBasePath()
const fieldProps = fieldPropsRef.value
const generateSlotsByProperties = (scoped = false) => {
if (props.onlyRenderSelf) return {}
const properties = Schema.getOrderProperties(fieldSchemaRef.value)
if (!properties.length) return {}
const renderMap: Record<string, ((field?: GeneralField) => unknown)[]> =
{}
const setRender = (
key: string,
value: (field?: GeneralField) => unknown
) => {
if (!renderMap[key]) {
renderMap[key] = []
}
renderMap[key].push(value)
}
properties.forEach(({ schema: item, key: name }, index) => {
let schema: Schema = item
if (isFn(props.mapProperties)) {
const mapped = props.mapProperties(item, name)
if (mapped) {
schema = mapped
}
}
if (isFn(props.filterProperties)) {
if (props.filterProperties(schema, name) === false) {
return null
}
}
setRender(schema['x-slot'] ?? 'default', (field?: GeneralField) =>
h(
RecursionField,
{
key: `${index}-${name}`,
attrs: {
schema,
name,
basePath: field?.address ?? basePath,
},
slot: schema['x-slot'],
},
{}
)
)
})
const slots = {}
Object.keys(renderMap).forEach((key) => {
const renderFns = renderMap[key]
slots[key] = scoped
? ({ field }) => renderFns.map((fn) => fn(field))
: () => renderFns.map((fn) => fn())
})
return slots
}
const render = () => {
if (!isValid(props.name))
return resolveEmptySlot(generateSlotsByProperties())
if (fieldSchemaRef.value.type === 'object') {
if (props.onlyRenderProperties)
return resolveEmptySlot(generateSlotsByProperties())
return h(
ObjectField,
{
attrs: {
...fieldProps,
name: props.name,
basePath: basePath,
},
},
generateSlotsByProperties(true)
)
} else if (fieldSchemaRef.value.type === 'array') {
return h(
ArrayField,
{
attrs: {
...fieldProps,
name: props.name,
basePath: basePath,
},
},
{}
)
} else if (fieldSchemaRef.value.type === 'void') {
if (props.onlyRenderProperties)
return resolveEmptySlot(generateSlotsByProperties())
const slots = generateSlotsByProperties(true)
return h(
VoidField,
{
attrs: {
...fieldProps,
name: props.name,
basePath: basePath,
},
},
slots
)
}
return h(
Field,
{
attrs: {
...fieldProps,
name: props.name,
basePath: basePath,
},
},
{}
)
}
if (!fieldSchemaRef.value) return
return render()
}
},