From 27cd65c89f37033ddc87b1d0449486f3610a4d55 Mon Sep 17 00:00:00 2001 From: J-Sek Date: Wed, 3 Dec 2025 11:54:22 +0100 Subject: [PATCH 1/2] fix(VTabs): support strict TS checks in templates --- packages/vuetify/src/components/VTabs/VTabs.tsx | 6 ++++-- .../vuetify/src/components/VTabs/VTabsWindow.tsx | 12 ++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/vuetify/src/components/VTabs/VTabs.tsx b/packages/vuetify/src/components/VTabs/VTabs.tsx index 49049cdc74e..dcbeca741bc 100644 --- a/packages/vuetify/src/components/VTabs/VTabs.tsx +++ b/packages/vuetify/src/components/VTabs/VTabs.tsx @@ -85,9 +85,11 @@ export const makeVTabsProps = propsFactory({ ...makeTagProps(), }, 'VTabs') -export const VTabs = genericComponent( +export const VTabs = genericComponent( props: { items?: T[] + modelValue?: TModel + 'onUpdate:modelValue'?: (value: TModel) => void }, slots: VTabsSlots ) => GenericProps>()({ @@ -96,7 +98,7 @@ export const VTabs = genericComponent( props: makeVTabsProps(), emits: { - 'update:modelValue': (v: unknown) => true, + 'update:modelValue': (v: any) => true, }, setup (props, { attrs, slots }) { diff --git a/packages/vuetify/src/components/VTabs/VTabsWindow.tsx b/packages/vuetify/src/components/VTabs/VTabsWindow.tsx index df9fb72b680..f5272283b95 100644 --- a/packages/vuetify/src/components/VTabs/VTabsWindow.tsx +++ b/packages/vuetify/src/components/VTabs/VTabsWindow.tsx @@ -10,18 +10,26 @@ import { genericComponent, omit, propsFactory, useRender } from '@/util' // Types import { VTabsSymbol } from './shared' +import type { VWindowSlots } from '@/components/VWindow/VWindow' +import type { GenericProps } from '@/util' export const makeVTabsWindowProps = propsFactory({ ...omit(makeVWindowProps(), ['continuous', 'nextIcon', 'prevIcon', 'showArrows', 'touch', 'mandatory']), }, 'VTabsWindow') -export const VTabsWindow = genericComponent()({ +export const VTabsWindow = genericComponent( + props: { + modelValue?: TModel + 'onUpdate:modelValue'?: (value: TModel) => void + }, + slots: VWindowSlots +) => GenericProps>()({ name: 'VTabsWindow', props: makeVTabsWindowProps(), emits: { - 'update:modelValue': (v: unknown) => true, + 'update:modelValue': (v: any) => true, }, setup (props, { slots }) { From 2350422f50d7b5d490e776b685720dfc636cd4de Mon Sep 17 00:00:00 2001 From: J-Sek Date: Wed, 3 Dec 2025 17:50:07 +0100 Subject: [PATCH 2/2] chore: cover similar components --- .../src/components/VDatePicker/VDatePickerMonth.tsx | 9 ++++++++- .../components/VExpansionPanel/VExpansionPanels.tsx | 9 ++++++++- packages/vuetify/src/components/VList/VList.tsx | 12 +++++------- .../vuetify/src/components/VStepper/VStepper.tsx | 10 ++++++++-- .../src/components/VStepper/VStepperWindow.tsx | 12 +++++++++++- packages/vuetify/src/components/VTabs/VTabs.tsx | 2 +- .../vuetify/src/components/VTreeview/VTreeview.tsx | 10 +++++++++- 7 files changed, 50 insertions(+), 14 deletions(-) diff --git a/packages/vuetify/src/components/VDatePicker/VDatePickerMonth.tsx b/packages/vuetify/src/components/VDatePicker/VDatePickerMonth.tsx index 24a98c4eac1..096ecc855b7 100644 --- a/packages/vuetify/src/components/VDatePicker/VDatePickerMonth.tsx +++ b/packages/vuetify/src/components/VDatePicker/VDatePickerMonth.tsx @@ -17,6 +17,7 @@ import { genericComponent, omit, propsFactory, useRender, wrapInArray } from '@/ // Types import type { PropType } from 'vue' +import type { GenericProps } from '@/util' export type DatePickerEventColorValue = boolean | string | string[] @@ -60,7 +61,13 @@ export const makeVDatePickerMonthProps = propsFactory({ ...omit(makeCalendarProps(), ['displayValue']), }, 'VDatePickerMonth') -export const VDatePickerMonth = genericComponent()({ +export const VDatePickerMonth = genericComponent( + props: { + modelValue?: TModel + 'onUpdate:modelValue'?: (value: TModel) => void + }, + slots: VDatePickerMonthSlots +) => GenericProps>()({ name: 'VDatePickerMonth', props: makeVDatePickerMonthProps(), diff --git a/packages/vuetify/src/components/VExpansionPanel/VExpansionPanels.tsx b/packages/vuetify/src/components/VExpansionPanel/VExpansionPanels.tsx index 173fd201ca5..2e3f7405c08 100644 --- a/packages/vuetify/src/components/VExpansionPanel/VExpansionPanels.tsx +++ b/packages/vuetify/src/components/VExpansionPanel/VExpansionPanels.tsx @@ -18,6 +18,7 @@ import { genericComponent, pick, propsFactory, useRender } from '@/util' // Types import type { PropType } from 'vue' +import type { GenericProps } from '@/util' const allowedVariants = ['default', 'accordion', 'inset', 'popout'] as const @@ -62,7 +63,13 @@ export const makeVExpansionPanelsProps = propsFactory({ }, }, 'VExpansionPanels') -export const VExpansionPanels = genericComponent()({ +export const VExpansionPanels = genericComponent( + props: { + modelValue?: TModel + 'onUpdate:modelValue'?: (value: TModel) => void + }, + slots: VExpansionPanelSlots +) => GenericProps>()({ name: 'VExpansionPanels', props: makeVExpansionPanelsProps(), diff --git a/packages/vuetify/src/components/VList/VList.tsx b/packages/vuetify/src/components/VList/VList.tsx index 662232432d7..ae152147c82 100644 --- a/packages/vuetify/src/components/VList/VList.tsx +++ b/packages/vuetify/src/components/VList/VList.tsx @@ -130,11 +130,7 @@ export const makeVListProps = propsFactory({ type ItemType = T extends readonly (infer U)[] ? U : never -export const VList = genericComponent( +export const VList = genericComponent( props: { items?: T itemTitle?: SelectItemKey> @@ -142,11 +138,13 @@ export const VList = genericComponent> itemProps?: SelectItemKey> selected?: S + activated?: A + opened?: O 'onUpdate:selected'?: (value: S) => void + 'onUpdate:activated'?: (value: A) => void + 'onUpdate:opened'?: (value: O) => void 'onClick:open'?: (value: { id: unknown, value: boolean, path: unknown[] }) => void 'onClick:select'?: (value: { id: unknown, value: boolean, path: unknown[] }) => void - opened?: O - 'onUpdate:opened'?: (value: O) => void }, slots: VListChildrenSlots> ) => GenericProps>()({ diff --git a/packages/vuetify/src/components/VStepper/VStepper.tsx b/packages/vuetify/src/components/VStepper/VStepper.tsx index f2293d3c62b..45b0c6a22ec 100644 --- a/packages/vuetify/src/components/VStepper/VStepper.tsx +++ b/packages/vuetify/src/components/VStepper/VStepper.tsx @@ -24,7 +24,7 @@ import { genericComponent, getPropertyFromItem, pick, propsFactory, useRender } // Types import type { PropType } from 'vue' import type { StepperItem, StepperItemSlot } from './VStepperItem' -import type { SelectItemKey } from '@/util' +import type { GenericProps, SelectItemKey } from '@/util' export type VStepperSlot = { prev: () => void @@ -87,7 +87,13 @@ export const makeVStepperProps = propsFactory({ ...pick(makeVStepperActionsProps(), ['prevText', 'nextText']), }, 'VStepper') -export const VStepper = genericComponent()({ +export const VStepper = genericComponent( + props: { + modelValue?: TModel + 'onUpdate:modelValue'?: (value: TModel) => void + }, + slots: VStepperSlots +) => GenericProps>()({ name: 'VStepper', props: makeVStepperProps(), diff --git a/packages/vuetify/src/components/VStepper/VStepperWindow.tsx b/packages/vuetify/src/components/VStepper/VStepperWindow.tsx index 146fec2fd28..e895816ec85 100644 --- a/packages/vuetify/src/components/VStepper/VStepperWindow.tsx +++ b/packages/vuetify/src/components/VStepper/VStepperWindow.tsx @@ -9,11 +9,21 @@ import { useProxiedModel } from '@/composables/proxiedModel' import { computed, inject } from 'vue' import { genericComponent, omit, propsFactory, useRender } from '@/util' +// Types +import type { VWindowSlots } from '@/components/VWindow/VWindow' +import type { GenericProps } from '@/util' + export const makeVStepperWindowProps = propsFactory({ ...omit(makeVWindowProps(), ['continuous', 'nextIcon', 'prevIcon', 'showArrows', 'touch', 'mandatory']), }, 'VStepperWindow') -export const VStepperWindow = genericComponent()({ +export const VStepperWindow = genericComponent( + props: { + modelValue?: TModel + 'onUpdate:modelValue'?: (value: TModel) => void + }, + slots: VWindowSlots +) => GenericProps>()({ name: 'VStepperWindow', props: makeVStepperWindowProps(), diff --git a/packages/vuetify/src/components/VTabs/VTabs.tsx b/packages/vuetify/src/components/VTabs/VTabs.tsx index dcbeca741bc..d24898708f0 100644 --- a/packages/vuetify/src/components/VTabs/VTabs.tsx +++ b/packages/vuetify/src/components/VTabs/VTabs.tsx @@ -98,7 +98,7 @@ export const VTabs = genericComponent( props: makeVTabsProps(), emits: { - 'update:modelValue': (v: any) => true, + 'update:modelValue': (v: unknown) => true, }, setup (props, { attrs, slots }) { diff --git a/packages/vuetify/src/components/VTreeview/VTreeview.tsx b/packages/vuetify/src/components/VTreeview/VTreeview.tsx index 23e84de7c07..1f77734fa3f 100644 --- a/packages/vuetify/src/components/VTreeview/VTreeview.tsx +++ b/packages/vuetify/src/components/VTreeview/VTreeview.tsx @@ -56,9 +56,17 @@ export const makeVTreeviewProps = propsFactory({ modelValue: Array, }, 'VTreeview') -export const VTreeview = genericComponent( +export const VTreeview = genericComponent( props: { items?: T[] + opened?: O + activated?: A + selected?: S + modelValue?: M + 'onUpdate:opened'?: (value: O) => void + 'onUpdate:activated'?: (value: A) => void + 'onUpdate:selected'?: (value: S) => void + 'onUpdate:modelValue'?: (value: M) => void }, slots: VTreeviewChildrenSlots & { 'no-data': never