/** * Create a basic component with common options */ import '../../locale'; import { camelize } from '..'; import { SlotsMixin } from '../../mixins/slots'; import Vue, { VNode, VueConstructor, ComponentOptions, RenderContext } from 'vue'; import { DefaultProps, FunctionComponent } from '../types'; export interface VantComponentOptions extends ComponentOptions { functional?: boolean; install?: (Vue: VueConstructor) => void; } export type TsxBaseProps = { key: string | number; // hack for jsx prop spread props: any; class: any; style: string | object[] | object; scopedSlots: Slots; }; export type TsxComponent = ( props: Partial> ) => VNode; const arrayProp = { type: Array, default: () => [] }; const numberProp = { type: Number, default: 0 }; function defaultProps(props: any) { Object.keys(props).forEach(key => { if (props[key] === Array) { props[key] = arrayProp; } else if (props[key] === Number) { props[key] = numberProp; } }); } function install(this: ComponentOptions, Vue: VueConstructor) { const { name } = this; Vue.component(name as string, this); Vue.component(camelize(`-${name}`), this); } // unify slots & scopedSlots export function unifySlots(context: RenderContext) { // use data.scopedSlots in lower Vue version const scopedSlots = context.scopedSlots || context.data.scopedSlots || {}; const slots = context.slots(); Object.keys(slots).forEach(key => { if (!scopedSlots[key]) { scopedSlots[key] = () => slots[key]; } }); return scopedSlots; } // should be removed after Vue 3 function transformFunctionComponent(pure: FunctionComponent): VantComponentOptions { return { functional: true, props: pure.props, model: pure.model, render: (h, context): any => pure(h, context.props, unifySlots(context), context) }; } export function useSFC(name: string) { return function ( sfc: VantComponentOptions | FunctionComponent ): TsxComponent { if (typeof sfc === 'function') { sfc = transformFunctionComponent(sfc); } if (!sfc.functional) { sfc.mixins = sfc.mixins || []; sfc.mixins.push(SlotsMixin); } if (sfc.props) { defaultProps(sfc.props); } sfc.name = name; sfc.install = install; return sfc as TsxComponent; }; }