Skip to content

Commit

Permalink
fix(VTab): inherit all VBtn props
Browse files Browse the repository at this point in the history
fixes #16918
  • Loading branch information
KaelWD committed Mar 17, 2023
1 parent 69dc8a2 commit 133b417
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 84 deletions.
78 changes: 40 additions & 38 deletions packages/vuetify/src/components/VBtn/VBtn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { useSelectLink } from '@/composables/selectLink'

// Utilities
import { computed } from 'vue'
import { genericComponent, useRender } from '@/util'
import { genericComponent, propsFactory, useRender } from '@/util'

// Types
import type { MakeSlots } from '@/util'
Expand All @@ -43,48 +43,50 @@ export type VBtnSlots = MakeSlots<{
loader: []
}>

export const VBtn = genericComponent<VBtnSlots>()({
name: 'VBtn',
export const makeVBtnProps = propsFactory({
active: {
type: Boolean,
default: undefined,
},
symbol: {
type: null,
default: VBtnToggleSymbol,
},
flat: Boolean,
icon: [Boolean, String, Function, Object] as PropType<boolean | IconValue>,
prependIcon: IconValue,
appendIcon: IconValue,

directives: { Ripple },
block: Boolean,
stacked: Boolean,

props: {
active: {
type: Boolean,
default: undefined,
},
symbol: {
type: null,
default: VBtnToggleSymbol,
},
flat: Boolean,
icon: [Boolean, String, Function, Object] as PropType<boolean | IconValue>,
prependIcon: IconValue,
appendIcon: IconValue,
ripple: {
type: Boolean,
default: true,
},

block: Boolean,
stacked: Boolean,
...makeBorderProps(),
...makeRoundedProps(),
...makeDensityProps(),
...makeDimensionProps(),
...makeElevationProps(),
...makeGroupItemProps(),
...makeLoaderProps(),
...makeLocationProps(),
...makePositionProps(),
...makeRouterProps(),
...makeSizeProps(),
...makeTagProps({ tag: 'button' }),
...makeThemeProps(),
...makeVariantProps({ variant: 'elevated' } as const),
}, 'VBtn')

ripple: {
type: Boolean,
default: true,
},
export const VBtn = genericComponent<VBtnSlots>()({
name: 'VBtn',

...makeBorderProps(),
...makeRoundedProps(),
...makeDensityProps(),
...makeDimensionProps(),
...makeElevationProps(),
...makeGroupItemProps(),
...makeLoaderProps(),
...makeLocationProps(),
...makePositionProps(),
...makeRouterProps(),
...makeSizeProps(),
...makeTagProps({ tag: 'button' }),
...makeThemeProps(),
...makeVariantProps({ variant: 'elevated' } as const),
},
directives: { Ripple },

props: makeVBtnProps(),

emits: {
'group:selected': (val: { value: boolean }) => true,
Expand Down
50 changes: 13 additions & 37 deletions packages/vuetify/src/components/VTabs/VTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,12 @@ import './VTab.sass'
import { VBtn } from '@/components/VBtn'

// Composables
import { IconValue } from '@/composables/icons'
import { makeGroupItemProps } from '@/composables/group'
import { makeRouterProps } from '@/composables/router'
import { makeTagProps } from '@/composables/tag'
import { makeThemeProps } from '@/composables/theme'
import { useTextColor } from '@/composables/color'

// Utilities
import { computed, ref } from 'vue'
import { animate, genericComponent, pick, standardEasing, useRender } from '@/util'
import { animate, genericComponent, omit, standardEasing, useRender } from '@/util'
import { makeVBtnProps } from '@/components/VBtn/VBtn'

// Types
import type { PropType } from 'vue'
Expand All @@ -25,18 +21,8 @@ export const VTab = genericComponent()({

props: {
fixed: Boolean,
icon: [Boolean, String, Function, Object] as PropType<boolean | IconValue>,
prependIcon: IconValue,
appendIcon: IconValue,

stacked: Boolean,
title: String,

ripple: {
type: Boolean,
default: true,
},
color: String,
sliderColor: String,
hideSlider: Boolean,

Expand All @@ -45,12 +31,17 @@ export const VTab = genericComponent()({
default: 'horizontal',
},

...makeTagProps(),
...makeRouterProps(),
...makeGroupItemProps({
...omit(makeVBtnProps({
selectedClass: 'v-tab--selected',
}),
...makeThemeProps(),
variant: 'text' as const,
}), [
'active',
'block',
'flat',
'location',
'position',
'symbol',
]),
},

setup (props, { slots, attrs }) {
Expand Down Expand Up @@ -110,21 +101,7 @@ export const VTab = genericComponent()({
}

useRender(() => {
const [btnProps] = pick(props, [
'href',
'to',
'replace',
'icon',
'stacked',
'prependIcon',
'appendIcon',
'ripple',
'theme',
'disabled',
'selectedClass',
'value',
'color',
])
const [btnProps] = VBtn.filterProps(props)

return (
<VBtn
Expand All @@ -140,7 +117,6 @@ export const VTab = genericComponent()({
active={ false }
block={ props.fixed }
maxWidth={ props.fixed ? 300 : undefined }
variant="text"
rounded={ 0 }
{ ...btnProps }
{ ...attrs }
Expand Down
88 changes: 79 additions & 9 deletions packages/vuetify/src/util/defineComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
watchEffect,
} from 'vue'
import { consoleWarn } from '@/util/console'
import { mergeDeep, toKebabCase } from '@/util/helpers'
import { mergeDeep, pick, toKebabCase } from '@/util/helpers'
import { injectSelf } from '@/util/injectSelf'
import { propsFactory } from '@/util/propsFactory'
import { DefaultsSymbol, provideDefaults, useDefaults } from '@/composables/defaults'
Expand All @@ -21,6 +21,7 @@ import type {
ComponentOptions,
ComponentOptionsMixin,
ComponentOptionsWithObjectProps,
ComponentOptionsWithoutProps,
ComponentPropsOptions,
ComputedOptions,
DefineComponent,
Expand All @@ -40,7 +41,66 @@ function propIsDefined (vnode: VNode, prop: string) {
typeof vnode.props?.[toKebabCase(prop)] !== 'undefined'
}

export const defineComponent = (function defineComponent (options: ComponentOptions) {
// 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
>(
options: ComponentOptionsWithoutProps<
Props,
RawBindings,
D,
C,
M,
Mixin,
Extends,
E,
EE,
I,
II
>
): DefineComponent<Props, RawBindings, D, C, M, Mixin, Extends, E, EE>

// Object Props
export function defineComponent<
PropsOptions extends Readonly<ComponentPropsOptions>,
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
>(
options: ComponentOptionsWithObjectProps<
PropsOptions,
RawBindings,
D,
C,
M,
Mixin,
Extends,
E,
EE,
I,
II
>
): DefineComponent<PropsOptions, RawBindings, D, C, M, Mixin, Extends, E, EE> & FilterPropsOptions<PropsOptions>

// Implementation
export function defineComponent (options: ComponentOptions) {
options._setup = options._setup ?? options.setup

if (!options.name) {
Expand All @@ -50,9 +110,11 @@ export const defineComponent = (function defineComponent (options: ComponentOpti
}

if (options._setup) {
options.props = options.props ?? {}

options.props = propsFactory(options.props, toKebabCase(options.name))()
options.props = propsFactory(options.props ?? {}, toKebabCase(options.name))()
const propKeys = Object.keys(options.props)
options.filterProps = function filterProps (props: Record<string, any>) {
return pick(props, propKeys)
}

options.props._as = String
options.setup = function setup (props: Record<string, any>, ctx) {
Expand Down Expand Up @@ -98,7 +160,7 @@ export const defineComponent = (function defineComponent (options: ComponentOpti
}

return options
}) as unknown as typeof _defineComponent
}

type ToListeners<T extends string | number | symbol> = { [K in T]: K extends `on${infer U}` ? Uncapitalize<U> : K }[T]

Expand Down Expand Up @@ -149,7 +211,7 @@ type DefineComponentWithGenericProps<T extends (new () => {
>
>(
options: ComponentOptionsWithObjectProps<PropsOptions, RawBindings, D, C, M, Mixin, Extends, E, EE>
) => Base & T
) => Base & T & FilterPropsOptions<PropsOptions>

type DefineComponentWithSlots<Slots extends Record<string, any[]> | Record<string, Slot>> = <
PropsOptions extends Readonly<ComponentPropsOptions>,
Expand All @@ -176,7 +238,7 @@ type DefineComponentWithSlots<Slots extends Record<string, any[]> | Record<strin
PublicProps,
ExtractPropTypes<PropsOptions> & SlotsToProps<Slots> & ({} extends E ? {} : EmitsToProps<E>),
ExtractDefaultPropTypes<PropsOptions>
>
> & FilterPropsOptions<PropsOptions>

// No argument - simple default slot
export function genericComponent (exposeDefaults?: boolean): DefineComponentWithSlots<{ default: [] }>
Expand All @@ -193,7 +255,7 @@ export function genericComponent<

// Implementation
export function genericComponent (exposeDefaults = true) {
return (options: any) => (exposeDefaults ? defineComponent : _defineComponent)(options) as any
return (options: any) => ((exposeDefaults ? defineComponent : _defineComponent) as any)(options)
}

export function defineFunctionalComponent<
Expand Down Expand Up @@ -229,3 +291,11 @@ type PublicProps =
& VNodeProps
& AllowedComponentProps
& ComponentCustomProps

// Adds a filterProps method to the component options
export interface FilterPropsOptions<PropsOptions extends Readonly<ComponentPropsOptions>, Props = ExtractPropTypes<PropsOptions>> {
filterProps<
T extends Partial<Props>,
U extends Exclude<keyof Props, Exclude<keyof Props, keyof T>>
> (props: T): [yes: Partial<Pick<T, U>>, no: Omit<T, U>]
}
2 changes: 2 additions & 0 deletions packages/vuetify/src/util/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,12 @@ type MaybePick<
U extends Extract<keyof T, string>
> = Record<string, unknown> extends T ? Partial<Pick<T, U>> : Pick<T, U>

// Array of keys
export function pick<
T extends object,
U extends Extract<keyof T, string>
> (obj: T, paths: U[]): [yes: MaybePick<T, U>, no: Omit<T, U>]
// Array of keys or RegExp to test keys against
export function pick<
T extends object,
U extends Extract<keyof T, string>
Expand Down

0 comments on commit 133b417

Please sign in to comment.