// Composables import { injectDefaults, internalUseDefaults } from '@/composables/defaults' // Utilities import { defineComponent as _defineComponent, // eslint-disable-line no-restricted-imports } from 'vue' import { consoleWarn } from '@/utils/console' import { pick } from '@/utils/helpers' import { propsFactory } from '@/utils/propsFactory' // Types import type { AllowedComponentProps, ComponentCustomProps, ComponentInjectOptions, ComponentObjectPropsOptions, ComponentOptions, ComponentOptionsMixin, ComponentOptionsWithObjectProps, ComponentOptionsWithoutProps, ComponentPropsOptions, ComputedOptions, DefineComponent, EmitsOptions, ExtractDefaultPropTypes, ExtractPropTypes, FunctionalComponent, MethodOptions, ObjectEmitsOptions, SlotsType, VNode, VNodeChild, VNodeProps, } from 'vue' // No props export function defineComponent< Props = {}, RawBindings = {}, D = {}, C extends ComputedOptions = {}, M extends MethodOptions = {}, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = {}, EE extends string = string, I extends {} = {}, II extends string = string, S extends SlotsType = {} >( options: ComponentOptionsWithoutProps< Props, RawBindings, D, C, M, Mixin, Extends, E, EE, I, II, S > ): DefineComponent // Object Props export function defineComponent< PropsOptions extends Readonly, RawBindings, D, C extends ComputedOptions = {}, M extends MethodOptions = {}, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = {}, EE extends string = string, I extends {} = {}, II extends string = string, S extends SlotsType = {} >( options: ComponentOptionsWithObjectProps< PropsOptions, RawBindings, D, C, M, Mixin, Extends, E, EE, I, II, S > ): DefineComponent & FilterPropsOptions // Implementation export function defineComponent(options: ComponentOptions) { options._setup = options._setup ?? options.setup if (!options.name) { consoleWarn( 'The component is missing an explicit name, unable to generate default prop value' ) return options } if (options._setup) { options.props = propsFactory(options.props ?? {}, options.name)() const propKeys = Object.keys(options.props) options.filterProps = function filterProps(props: Record) { return pick(props, propKeys, ['class', 'style']) } options.props._as = String options.setup = function setup(props: Record, ctx) { const defaults = injectDefaults() // Skip props proxy if defaults are not provided if (!defaults.value) return options._setup(props, ctx) const { props: _props, provideSubDefaults } = internalUseDefaults( props, props._as ?? options.name, defaults ) const setupBindings = options._setup(_props, ctx) provideSubDefaults() return setupBindings } } return options } type ToListeners = { [K in T]: K extends `on${infer U}` ? Uncapitalize : K }[T] export type SlotsToProps> = { $children?: | VNodeChild | (T extends { default: infer V } ? V : {}) | { [K in keyof T]?: T[K] } 'v-slots'?: { [K in keyof T]?: T[K] | false } } & { [K in keyof T as `v-slot:${K & string}`]?: T[K] | false } type RawSlots = Record type Slot = [T] extends [never] ? () => VNodeChild : (arg: T) => VNodeChild type VueSlot = [T] extends [never] ? () => VNode[] : (arg: T) => VNode[] type MakeInternalSlots = { [K in keyof T]: Slot } type MakeSlots = { [K in keyof T]: VueSlot } export type GenericProps> = { $props: Props & SlotsToProps $slots: MakeSlots } type DefineComponentWithGenericProps< T extends new (props: Record, slots: RawSlots) => { $props?: Record } > = < PropsOptions extends Readonly, RawBindings, D, C extends ComputedOptions = {}, M extends MethodOptions = {}, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = Record, EE extends string = string, I extends ComponentInjectOptions = {}, II extends string = string, // Slots extends RawSlots = ConstructorParameters extends [any, infer SS extends RawSlots | undefined] ? Exclude : {}, Slots extends RawSlots = ConstructorParameters[1], S extends SlotsType = SlotsType>>, III = InstanceType, P = III extends Record<'$props', any> ? Omit : PropsOptions, Base = DefineComponent< P, RawBindings, D, C, M, Mixin, Extends, E extends any[] ? E : III extends Record<'$props', any> ? Omit> : E, EE, PublicProps, ExtractPropTypes

& ({} extends E ? {} : EmitsToProps), ExtractDefaultPropTypes

, S > >( options: ComponentOptionsWithObjectProps< PropsOptions, RawBindings, D, C, M, Mixin, Extends, E, EE, I, II, S > ) => Base & T & FilterPropsOptions type DefineComponentWithSlots = < PropsOptions extends Readonly, RawBindings, D, C extends ComputedOptions = {}, M extends MethodOptions = {}, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = Record, EE extends string = string, I extends ComponentInjectOptions = {}, II extends string = string, S extends SlotsType = SlotsType>> >( options: ComponentOptionsWithObjectProps< PropsOptions, RawBindings, D, C, M, Mixin, Extends, E, EE, I, II, S > ) => DefineComponent< ExtractPropTypes & SlotsToProps, RawBindings, D, C, M, Mixin, Extends, E, EE, PublicProps, ExtractPropTypes & SlotsToProps & ({} extends E ? {} : EmitsToProps), ExtractDefaultPropTypes, S > & FilterPropsOptions // No argument - simple default slot export function genericComponent( exposeDefaults?: boolean ): DefineComponentWithSlots<{ default: never }> // Generic constructor argument - generic props and slots export function genericComponent< T extends new (props: Record, slots: any) => { $props?: Record } >(exposeDefaults?: boolean): DefineComponentWithGenericProps // Slots argument - simple slots export function genericComponent( exposeDefaults?: boolean ): DefineComponentWithSlots // Implementation export function genericComponent(exposeDefaults = true) { return (options: any) => ((exposeDefaults ? defineComponent : _defineComponent) as any)(options) } export function defineFunctionalComponent< T extends FunctionalComponent, PropsOptions = ComponentObjectPropsOptions, Defaults = ExtractDefaultPropTypes, Props = Readonly> >( props: PropsOptions, render: T ): FunctionalComponent & Omit> { render.props = props as any return render as any } type EmitsToProps = T extends string[] ? { [K in string & `on${Capitalize}`]?: (...args: any[]) => any } : T extends ObjectEmitsOptions ? { [K in string & `on${Capitalize}`]?: K extends `on${infer C}` ? T[Uncapitalize] extends null ? (...args: any[]) => any : ( ...args: T[Uncapitalize] extends (...args: infer P) => any ? P : never ) => any : never } : {} type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps // Adds a filterProps method to the component options export interface FilterPropsOptions< PropsOptions extends Readonly, Props = ExtractPropTypes > { filterProps< T extends Partial, U extends Exclude> >( props: T ): [yes: Partial>, no: Omit] }