<script setup>
import { computed, defineModel } from 'vue';

const model = defineModel(undefined, { required: true });
const $props = defineProps({
    prop: {
        type: Object,
        required: true,
    },
    components: {
        type: Object,
        default: () => {},
    },
    value: {
        type: [Object, Number, String, Boolean],
        default: () => {},
    },
});

const componentArray = computed(() => {
    if (typeof $props.prop === 'object') return [$props.prop];
    return $props.prop;
});

function mix(toComponent) {
    const { component, attrs, event } = toComponent;
    const customComponent = $props.components[component];
    return {
        component: customComponent?.component ?? component,
        attrs: {
            ...toValueAttrs(attrs),
            ...toValueAttrs(customComponent?.attrs),
            ...toComponent,
            ...toValueAttrs(customComponent?.forceAttrs),
        },
        event: { ...customComponent?.event, ...event },
    };
}

function toValueAttrs(attrs) {
    if (!attrs) return;
    return typeof attrs == 'function' ? attrs($props.value) : attrs;
}
</script>
<template>
    <span
        v-for="toComponent of componentArray"
        :key="toComponent.name"
        class="column flex-center fit"
    >
        <component
            v-if="toComponent?.component"
            :is="mix(toComponent).component"
            v-bind="mix(toComponent).attrs"
            v-on="mix(toComponent).event ?? {}"
            v-model="model"
        />
    </span>
</template>
