GitHub

@@ -149,7 +149,7 @@ export interface SelectSlots<

149149150150

<script setup lang="ts" generic="T extends ArrayOrNested<SelectItem>, VK extends GetItemKeys<T> = 'value', M extends boolean = false, Mod extends Omit<ModelModifiers, 'lazy'> = Omit<ModelModifiers, 'lazy'>">

151151

import { useTemplateRef, computed, onMounted, toRef } from 'vue'

152-

import { SelectRoot, SelectArrow, SelectTrigger, SelectPortal, SelectContent, SelectLabel, SelectGroup, SelectItem as RSelectItem, SelectItemIndicator, SelectItemText, SelectSeparator, useForwardPropsEmits } from 'reka-ui'

152+

import { SelectRoot, SelectArrow, SelectTrigger, SelectPortal, SelectContent, SelectViewport, SelectValue as RSelectValue, SelectLabel, SelectGroup, SelectItem as RSelectItem, SelectItemIndicator, SelectItemText, SelectSeparator, useForwardPropsEmits } from 'reka-ui'

153153

import { defu } from 'defu'

154154

import { reactivePick } from '@vueuse/core'

155155

import { useAppConfig } from '#imports'

@@ -181,7 +181,11 @@ const uiProp = useComponentUI('select', props)

181181182182

const rootProps = useForwardPropsEmits(reactivePick(props, 'open', 'defaultOpen', 'disabled', 'autocomplete', 'required', 'multiple'), emits)

183183

const portalProps = usePortal(toRef(() => props.portal))

184-

const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }) as SelectContentProps)

184+

// Resolve `position` from props > `app.config.ts` `defaultVariants` > hardcoded default,

185+

// so both the template logic (`isItemAligned`) and the Reka UI primitive see the same value.

186+

// `tv()` only applies `defaultVariants` to classes, not to runtime logic (see #6360).

187+

const position = computed(() => props.content?.position ?? appConfig.ui?.select?.defaultVariants?.position ?? 'popper')

188+

const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: position.value }) as SelectContentProps)

185189

const arrowProps = toRef(() => defu(props.arrow, { rounded: true }) as SelectArrowProps)

186190187191

const { emitFormChange, emitFormInput, emitFormBlur, emitFormFocus, size: formFieldSize, color, id, name, highlight, disabled, ariaAttrs } = useFormField<InputProps>(props)

@@ -190,6 +194,8 @@ const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponen

190194191195

const selectSize = computed(() => fieldGroupSize.value || formFieldSize.value)

192196197+

const isItemAligned = computed(() => position.value === 'item-aligned')

198+193199

const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.select || {}) })({

194200

color: color.value,

195201

variant: props.variant,

@@ -198,7 +204,8 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.select || {}

198204

highlight: highlight.value,

199205

leading: isLeading.value || !!props.avatar || !!slots.leading,

200206

trailing: isTrailing.value || !!slots.trailing,

201-

fieldGroup: orientation.value

207+

fieldGroup: orientation.value,

208+

position: position.value

202209

}))

203210204211

const groups = computed<SelectItem[][]>(() =>

@@ -289,7 +296,10 @@ const viewportRef = useTemplateRef('viewportRef')

289296290297

defineExpose({

291298

triggerRef: toRef(() => triggerRef.value?.$el as HTMLButtonElement),

292-

viewportRef: toRef(() => viewportRef.value)

299+

viewportRef: toRef(() => {

300+

const instance = viewportRef.value

301+

return (instance && typeof instance === 'object' && '$el' in instance ? instance.$el : instance) as HTMLElement | null

302+

})

293303

})

294304

</script>

295305

@@ -320,16 +330,16 @@ defineExpose({

320330

</slot>

321331

</span>

322332323-

<slot :model-value="(modelValue as ApplyModifiers<GetModelValue<T, VK, M, ExcludeItem>, Mod>)" :open="open" :ui="ui">

324-

<template v-for="displayedModelValue in [displayValue(modelValue as any)]" :key="displayedModelValue">

325-

<span v-if="displayedModelValue !== undefined && displayedModelValue !== null" data-slot="value" :class="ui.value({ class: uiProp?.value })">

326-

{{ displayedModelValue }}

327-

</span>

328-

<span v-else data-slot="placeholder" :class="ui.placeholder({ class: uiProp?.placeholder })">

329-

{{ placeholder ?? '&nbsp;' }}

330-

</span>

331-

</template>

332-

</slot>

333+

<template v-for="displayedModelValue in [displayValue(modelValue as any)]" :key="displayedModelValue">

334+

<RSelectValue

335+

:data-slot="displayedModelValue != null ? 'value' : 'placeholder'"

336+

:class="displayedModelValue != null ? ui.value({ class: uiProp?.value }) : ui.placeholder({ class: uiProp?.placeholder })"

337+

>

338+

<slot :model-value="(modelValue as ApplyModifiers<GetModelValue<T, VK, M, ExcludeItem>, Mod>)" :open="open" :ui="ui">

339+

{{ displayedModelValue ?? (placeholder ?? '&nbsp;') }}

340+

</slot>

341+

</RSelectValue>

342+

</template>

333343334344

<span v-if="isTrailing || !!slots.trailing" data-slot="trailing" :class="ui.trailing({ class: uiProp?.trailing })">

335345

<slot name="trailing" :model-value="(modelValue as ApplyModifiers<GetModelValue<T, VK, M, ExcludeItem>, Mod>)" :open="open" :ui="ui">

@@ -343,7 +353,7 @@ defineExpose({

343353

<SelectContent data-slot="content" :class="ui.content({ class: uiProp?.content })" v-bind="contentProps">

344354

<slot name="content-top" />

345355346-

<div ref="viewportRef" role="presentation" data-slot="viewport" :class="ui.viewport({ class: uiProp?.viewport })">

356+

<component :is="isItemAligned ? SelectViewport : 'div'" ref="viewportRef" role="presentation" data-slot="viewport" :class="ui.viewport({ class: uiProp?.viewport })">

347357

<SelectGroup v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" data-slot="group" :class="ui.group({ class: uiProp?.group })">

348358

<template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">

349359

<SelectLabel v-if="isSelectItem(item) && item.type === 'label'" data-slot="label" :class="ui.label({ class: [uiProp?.label, item.ui?.label, item.class] })">

@@ -400,7 +410,7 @@ defineExpose({

400410

</RSelectItem>

401411

</template>

402412

</SelectGroup>

403-

</div>

413+

</component>

404414405415

<slot name="content-bottom" />

406416

Read the original on github.com ↗