fix(components): class should have priority over ui prop

This commit is contained in:
Benjamin Canac
2025-05-07 17:23:27 +02:00
parent a655da1394
commit e6e510b848
39 changed files with 40 additions and 40 deletions

View File

@@ -66,7 +66,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.${camelName}
</script>
<template>
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
<slot />
</Primitive>
</template>
@@ -109,7 +109,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.${camelName}
</script>
<template>
<${upperName}Root v-bind="rootProps" :class="ui.root({ class: [props.class, props.ui?.root] })" />
<${upperName}Root v-bind="rootProps" :class="ui.root({ class: [props.ui?.root, props.class] })" />
</template>
`
}

View File

@@ -973,7 +973,7 @@ export default {
```vue [src/runtime/components/Card.vue]
<template>
<div :class="ui.root({ class: [props.class, props.ui?.root] })">
<div :class="ui.root({ class: [props.ui?.root, props.class] })">
<div :class="ui.header({ class: props.ui?.header })">
<slot name="header" />
</div>

View File

@@ -89,7 +89,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.accordion ||
</script>
<template>
<AccordionRoot v-bind="rootProps" :class="ui.root({ class: [props.class, props.ui?.root] })">
<AccordionRoot v-bind="rootProps" :class="ui.root({ class: [props.ui?.root, props.class] })">
<AccordionItem
v-for="(item, index) in props.items"
v-slot="{ open }"

View File

@@ -97,7 +97,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.alert || {})
</script>
<template>
<Primitive :as="as" :data-orientation="orientation" :class="ui.root({ class: [props.class, props.ui?.root] })">
<Primitive :as="as" :data-orientation="orientation" :class="ui.root({ class: [props.ui?.root, props.class] })">
<slot name="leading">
<UAvatar v-if="avatar" :size="((props.ui?.avatarSize || ui.avatarSize()) as AvatarProps['size'])" v-bind="avatar" :class="ui.avatar({ class: props.ui?.avatar })" />
<UIcon v-else-if="icon" :name="icon" :class="ui.icon({ class: props.ui?.icon })" />

View File

@@ -81,7 +81,7 @@ function onError() {
</script>
<template>
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })" :style="props.style">
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })" :style="props.style">
<component
:is="ImageComponent"
v-if="src && !error"

View File

@@ -93,7 +93,7 @@ provide(avatarGroupInjectionKey, computed(() => ({
</script>
<template>
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
<UAvatar v-if="hiddenCount > 0" :text="`+${hiddenCount}`" :class="ui.base({ class: props.ui?.base })" />
<component :is="avatar" v-for="(avatar, count) in visibleAvatars" :key="count" :class="ui.base({ class: props.ui?.base })" />
</Primitive>

View File

@@ -65,7 +65,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.badge || {})
</script>
<template>
<Primitive :as="as" :class="ui.base({ class: [props.class, props.ui?.base] })">
<Primitive :as="as" :class="ui.base({ class: [props.ui?.base, props.class] })">
<slot name="leading">
<UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
<UAvatar v-else-if="!!avatar" :size="((props.ui?.leadingAvatarSize || ui.leadingAvatarSize()) as AvatarProps['size'])" v-bind="avatar" :class="ui.leadingAvatar({ class: props.ui?.leadingAvatar })" />

View File

@@ -81,7 +81,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.breadcrumb |
</script>
<template>
<Primitive :as="as" aria-label="breadcrumb" :class="ui.root({ class: [props.class, props.ui?.root] })">
<Primitive :as="as" aria-label="breadcrumb" :class="ui.root({ class: [props.ui?.root, props.class] })">
<ol :class="ui.list({ class: props.ui?.list })">
<template v-for="(item, index) in items" :key="index">
<li :class="ui.item({ class: props.ui?.item })">

View File

@@ -123,7 +123,7 @@ const ui = computed(() => tv({
v-slot="{ active, ...slotProps }"
:type="type"
:disabled="disabled || isLoading"
:class="ui.base({ class: [props.class, props.ui?.base] })"
:class="ui.base({ class: [props.ui?.base, props.class] })"
v-bind="omit(linkProps, ['type', 'disabled', 'onClick'])"
custom
>

View File

@@ -157,7 +157,7 @@ const Calendar = computed(() => props.range ? RangeCalendar : SingleCalendar)
:default-value="defaultValue"
:locale="locale"
:dir="dir"
:class="ui.root({ class: [props.class, props.ui?.root] })"
:class="ui.root({ class: [props.ui?.root, props.class] })"
>
<Calendar.Header :class="ui.header({ class: props.ui?.header })">
<Calendar.Prev v-if="props.yearControls" :prev-page="(date: DateValue) => paginateYear(date, -1)" :aria-label="t('calendar.prevYear')" as-child>

View File

@@ -43,7 +43,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.card || {})
</script>
<template>
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
<div v-if="!!slots.header" :class="ui.header({ class: props.ui?.header })">
<slot name="header" />
</div>

View File

@@ -278,7 +278,7 @@ defineExpose({
role="region"
aria-roledescription="carousel"
tabindex="0"
:class="ui.root({ class: [props.class, props.ui?.root] })"
:class="ui.root({ class: [props.ui?.root, props.class] })"
@keydown="onKeyDown"
>
<div ref="emblaRef" :class="ui.viewport({ class: props.ui?.viewport })">

View File

@@ -101,7 +101,7 @@ function onUpdate(value: any) {
<!-- eslint-disable vue/no-template-shadow -->
<template>
<Primitive :as="variant === 'list' ? as : Label" :class="ui.root({ class: [props.class, props.ui?.root] })">
<Primitive :as="variant === 'list' ? as : Label" :class="ui.root({ class: [props.ui?.root, props.class] })">
<div :class="ui.container({ class: props.ui?.container })">
<CheckboxRoot
:id="id"

View File

@@ -153,7 +153,7 @@ function onUpdate(value: any) {
v-bind="rootProps"
:name="name"
:disabled="disabled"
:class="ui.root({ class: [props.class, props.ui?.root] })"
:class="ui.root({ class: [props.ui?.root, props.class] })"
@update:model-value="onUpdate"
>
<fieldset :class="ui.fieldset({ class: props.ui?.fieldset })" v-bind="ariaAttrs">

View File

@@ -74,7 +74,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.chip || {})
</script>
<template>
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
<Slot v-bind="$attrs">
<slot />
</Slot>

View File

@@ -46,7 +46,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.collapsible
</script>
<template>
<CollapsibleRoot v-slot="{ open }" v-bind="rootProps" :class="ui.root({ class: [props.class, props.ui?.root] })">
<CollapsibleRoot v-slot="{ open }" v-bind="rootProps" :class="ui.root({ class: [props.ui?.root, props.class] })">
<CollapsibleTrigger v-if="!!slots.default" as-child>
<slot :open="open" />
</CollapsibleTrigger>

View File

@@ -263,7 +263,7 @@ const trackThumbStyle = computed(() => ({
</script>
<template>
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })" :data-disabled="disabled ? true : undefined">
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })" :data-disabled="disabled ? true : undefined">
<div :class="ui.picker({ class: props.ui?.picker })">
<div
ref="selectorRef"

View File

@@ -249,7 +249,7 @@ const groups = computed(() => {
<!-- eslint-disable vue/no-v-html -->
<template>
<ListboxRoot v-bind="rootProps" :class="ui.root({ class: [props.class, props.ui?.root] })">
<ListboxRoot v-bind="rootProps" :class="ui.root({ class: [props.ui?.root, props.class] })">
<ListboxFilter v-model="searchTerm" as-child>
<UInput
:placeholder="placeholder || t('commandPalette.placeholder')"

View File

@@ -90,7 +90,7 @@ provide(formFieldInjectionKey, computed(() => ({
</script>
<template>
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
<div :class="ui.wrapper({ class: props.ui?.wrapper })">
<div v-if="label || !!slots.label" :class="ui.labelWrapper({ class: props.ui?.labelWrapper })">
<Label :for="id" :class="ui.label({ class: props.ui?.label })">

View File

@@ -163,7 +163,7 @@ defineExpose({
</script>
<template>
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
<input
:id="id"
ref="inputRef"

View File

@@ -406,7 +406,7 @@ defineExpose({
v-bind="rootProps"
:name="name"
:disabled="disabled"
:class="ui.root({ class: [props.class, props.ui?.root] })"
:class="ui.root({ class: [props.ui?.root, props.class] })"
:as-child="!!multiple"
ignore-filter
@update:model-value="onUpdate"

View File

@@ -145,7 +145,7 @@ defineExpose({
<NumberFieldRoot
v-bind="rootProps"
:id="id"
:class="ui.root({ class: [props.class, props.ui?.root] })"
:class="ui.root({ class: [props.ui?.root, props.class] })"
:name="name"
:disabled="disabled"
:locale="locale"

View File

@@ -304,7 +304,7 @@ const lists = computed<NavigationMenuItem[][]>(() =>
</component>
</DefineItemTemplate>
<NavigationMenuRoot v-bind="rootProps" :data-collapsed="collapsed" :class="ui.root({ class: [props.class, props.ui?.root] })">
<NavigationMenuRoot v-bind="rootProps" :data-collapsed="collapsed" :class="ui.root({ class: [props.ui?.root, props.class] })">
<slot name="list-leading" />
<template v-for="(list, listIndex) in lists" :key="`list-${listIndex}`">

View File

@@ -140,7 +140,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.pagination |
</script>
<template>
<PaginationRoot v-slot="{ page, pageCount }" v-bind="rootProps" :class="ui.root({ class: [props.class, props.ui?.root] })">
<PaginationRoot v-slot="{ page, pageCount }" v-bind="rootProps" :class="ui.root({ class: [props.ui?.root, props.class] })">
<PaginationList v-slot="{ items }" :class="ui.list({ class: props.ui?.list })">
<PaginationFirst v-if="showControls || !!slots.first" as-child :class="ui.first({ class: props.ui?.first })">
<slot name="first">

View File

@@ -113,7 +113,7 @@ defineExpose({
v-bind="{ ...rootProps, ...ariaAttrs }"
:id="id"
:name="name"
:class="ui.root({ class: [props.class, props.ui?.root] })"
:class="ui.root({ class: [props.ui?.root, props.class] })"
@update:model-value="emitFormInput()"
@complete="onComplete"
>

View File

@@ -167,7 +167,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.progress ||
</script>
<template>
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
<div v-if="!isIndeterminate && (status || !!slots.status)" :class="ui.status({ class: props.ui?.status })" :style="statusStyle">
<slot name="status" :percent="percent">
{{ percent }}%

View File

@@ -166,7 +166,7 @@ function onUpdate(value: any) {
v-bind="rootProps"
:name="name"
:disabled="disabled"
:class="ui.root({ class: [props.class, props.ui?.root] })"
:class="ui.root({ class: [props.ui?.root, props.class] })"
@update:model-value="onUpdate"
>
<fieldset :class="ui.fieldset({ class: props.ui?.fieldset })" v-bind="ariaAttrs">

View File

@@ -238,7 +238,7 @@ function isSelectItem(item: SelectItem): item is SelectItemBase {
@update:model-value="onUpdate"
@update:open="onUpdateOpen"
>
<SelectTrigger :id="id" :class="ui.base({ class: [props.class, props.ui?.base] })" v-bind="{ ...$attrs, ...ariaAttrs }">
<SelectTrigger :id="id" :class="ui.base({ class: [props.ui?.base, props.class] })" v-bind="{ ...$attrs, ...ariaAttrs }">
<span v-if="isLeading || !!avatar || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
<slot name="leading" :model-value="(modelValue as GetModelValue<T, VK, M>)" :open="open" :ui="ui">
<UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />

View File

@@ -373,7 +373,7 @@ function isSelectItem(item: SelectMenuItem): item is _SelectMenuItem {
@update:open="onUpdateOpen"
>
<ComboboxAnchor as-child>
<ComboboxTrigger :class="ui.base({ class: [props.class, props.ui?.base] })" tabindex="0">
<ComboboxTrigger :class="ui.base({ class: [props.ui?.base, props.class] })" tabindex="0">
<span v-if="isLeading || !!avatar || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
<slot name="leading" :model-value="(modelValue as GetModelValue<T, VK, M>)" :open="open" :ui="ui">
<UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />

View File

@@ -75,7 +75,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.separator ||
</script>
<template>
<Separator v-bind="rootProps" :class="ui.root({ class: [props.class, props.ui?.root] })">
<Separator v-bind="rootProps" :class="ui.root({ class: [props.ui?.root, props.class] })">
<div :class="ui.border({ class: props.ui?.border })" />
<template v-if="label || icon || avatar || !!slots.default">

View File

@@ -104,7 +104,7 @@ function onChange(value: any) {
v-model="sliderValue"
:name="name"
:disabled="disabled"
:class="ui.root({ class: [props.class, props.ui?.root] })"
:class="ui.root({ class: [props.ui?.root, props.class] })"
:default-value="defaultSliderValue"
@update:model-value="emitFormInput()"
@value-commit="onChange"

View File

@@ -129,7 +129,7 @@ defineExpose({
</script>
<template>
<StepperRoot v-bind="rootProps" v-model="currentStepIndex" :class="ui.root({ class: [props.class, props.ui?.root] })">
<StepperRoot v-bind="rootProps" v-model="currentStepIndex" :class="ui.root({ class: [props.ui?.root, props.class] })">
<div :class="ui.header({ class: props.ui?.header })">
<StepperItem
v-for="(item, count) in items"

View File

@@ -96,7 +96,7 @@ function onUpdate(value: any) {
</script>
<template>
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
<div :class="ui.container({ class: props.ui?.container })">
<SwitchRoot
:id="id"

View File

@@ -338,7 +338,7 @@ defineExpose({
</script>
<template>
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
<table ref="tableRef" :class="ui.base({ class: [props.ui?.base] })">
<caption v-if="caption || !!slots.caption" :class="ui.caption({ class: [props.ui?.caption] })">
<slot name="caption">

View File

@@ -109,7 +109,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.tabs || {})
</script>
<template>
<TabsRoot v-bind="rootProps" :class="ui.root({ class: [props.class, props.ui?.root] })">
<TabsRoot v-bind="rootProps" :class="ui.root({ class: [props.ui?.root, props.class] })">
<TabsList :class="ui.list({ class: props.ui?.list })">
<TabsIndicator :class="ui.indicator({ class: props.ui?.indicator })" />

View File

@@ -190,7 +190,7 @@ defineExpose({
</script>
<template>
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
<textarea
:id="id"
ref="textareaRef"

View File

@@ -116,7 +116,7 @@ defineExpose({
v-slot="{ remaining, duration }"
v-bind="rootProps"
:data-orientation="orientation"
:class="ui.root({ class: [props.class, props.ui?.root] })"
:class="ui.root({ class: [props.ui?.root, props.class] })"
:style="{ '--height': height }"
>
<slot name="leading">

View File

@@ -131,7 +131,7 @@ function getOffset(index: number) {
<ToastPortal v-bind="portalProps">
<ToastViewport
:data-expanded="expanded"
:class="ui.viewport({ class: [props.class, props.ui?.viewport] })"
:class="ui.viewport({ class: [props.ui?.viewport, props.class] })"
:style="{
'--scale-factor': '0.05',
'--translate-factor': position?.startsWith('top') ? '1px' : '-1px',

View File

@@ -198,7 +198,7 @@ const defaultExpanded = computed(() =>
<TreeRoot
v-bind="(rootProps as unknown as TreeRootProps<NestedItem<T>>)"
:class="ui.root({ class: [props.class, props.ui?.root] })"
:class="ui.root({ class: [props.ui?.root, props.class] })"
:get-key="getItemValue"
:default-expanded="defaultExpanded"
:selection-behavior="selectionBehavior"