InputMenu
Usage
v-model 지시문을 사용하여 InputMenu의 값을 제어하거나 default-value prop의 상태를 제어할 필요가 없을 때 초기 값을 설정합니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" :items="items" />
</template>SelectMenu와 비슷하지만 Select 대신 Input을 사용합니다.Items 항목
items prop을 문자열, 숫자 또는 부울 배열로 사용합니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" :items="items" />
</template>또한 다음 속성을 사용하여 객체 배열을 전달할 수 있습니다.
label?: stringtype?: "label" | "separator" | "item"icon?: stringavatar?: AvatarPropschip?: ChipPropsdisabled?: boolean- {lang="ts-type"}onSelect?: (e: Event) => void(-onSelect?: (e: Event) => void)class?: anyui?: { tagsItem?: ClassNameValue, tagsItemText?: ClassNameValue, tagsItemDelete?: ClassNameValue, tagsItemDeleteIcon?: ClassNameValue, label?: ClassNameValue, separator?: ClassNameValue, item?: ClassNameValue, itemLeadingIcon?: ClassNameValue, itemLeadingAvatarSize?: ClassNameValue, itemLeadingAvatar?: ClassNameValue, itemLeadingChip?: ClassNameValue, itemLeadingChipSize?: ClassNameValue, itemLabel?: ClassNameValue, itemTrailing?: ClassNameValue, itemTrailingIcon?: ClassNameValue }(-ui?: { tagsItem?: ClassNameValue, tagsItemText?: ClassNameValue, tagsItemDelete?: ClassNameValue, tagsItemDeleteIcon?: ClassNameValue, label?: ClassNameValue, separator?: ClassNameValue, item?: ClassNameValue, itemLeadingIcon?: ClassNameValue, itemLeadingAvatarSize?: ClassNameValue, itemLeadingAvatar?: ClassNameValue, itemLeadingChip?: ClassNameValue, itemLeadingChipSize?: ClassNameValue, itemLabel?: ClassNameValue, itemTrailing?: ClassNameValue, itemTrailingIcon?: ClassNameValue })
<script setup lang="ts">
import type { InputMenuItem } from '@nuxt/ui'
const items = ref<InputMenuItem[]>([
{
label: 'Backlog'
},
{
label: 'Todo'
},
{
label: 'In Progress'
},
{
label: 'Done'
}
])
const value = ref({
label: 'Todo'
})
</script>
<template>
<UInputMenu v-model="value" :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
import type { InputMenuItem } from '@nuxt/ui'
const items = ref<InputMenuItem[]>([
{
label: 'Backlog'
},
{
label: 'Todo'
},
{
label: 'In Progress'
},
{
label: 'Done'
}
])
const value = ref({
label: 'Todo'
})
</script>
<template>
<UInputMenu v-model="value" :items="items" />
</template>배열 배열을 items prop에 전달하여 개별 항목 그룹을 표시할 수도 있습니다.
<script setup lang="ts">
const items = ref([
['Apple', 'Banana', 'Blueberry', 'Grapes', 'Pineapple'],
['Aubergine', 'Broccoli', 'Carrot', 'Courgette', 'Leek']
])
const value = ref('Apple')
</script>
<template>
<UInputMenu v-model="value" :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref([
['Apple', 'Banana', 'Blueberry', 'Grapes', 'Pineapple'],
['Aubergine', 'Broccoli', 'Carrot', 'Courgette', 'Leek']
])
const value = ref('Apple')
</script>
<template>
<UInputMenu v-model="value" :items="items" />
</template>값 키
value-key prop. 기본값은 undefined로 설정하여 전체 오브젝트가 아닌 오브젝트의 단일 속성을 바인딩하도록 선택할 수 있습니다.
<script setup lang="ts">
import type { InputMenuItem } from '@nuxt/ui'
const items = ref<InputMenuItem[]>([
{
label: 'Backlog',
id: 'backlog'
},
{
label: 'Todo',
id: 'todo'
},
{
label: 'In Progress',
id: 'in_progress'
},
{
label: 'Done',
id: 'done'
}
])
const value = ref('todo')
</script>
<template>
<UInputMenu v-model="value" value-key="id" :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
import type { InputMenuItem } from '@nuxt/ui'
const items = ref<InputMenuItem[]>([
{
label: 'Backlog',
id: 'backlog'
},
{
label: 'Todo',
id: 'todo'
},
{
label: 'In Progress',
id: 'in_progress'
},
{
label: 'Done',
id: 'done'
}
])
const value = ref('todo')
</script>
<template>
<UInputMenu v-model="value" value-key="id" :items="items" />
</template>model-value가 객체인 경우 참조 대신 필드로 객체를 비교하려면 by prop을 사용합니다.다중 입력
multiple 소품을 사용하여 여러 선택을 허용하면 선택한 항목이 태그로 표시됩니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref(['Backlog', 'Todo'])
</script>
<template>
<UInputMenu v-model="value" multiple :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref(['Backlog', 'Todo'])
</script>
<template>
<UInputMenu v-model="value" multiple :items="items" />
</template>default-value prop 또는 v-model 지시문으로 전달해야 합니다.아이콘 삭제
multiple를 사용하면 delete-icon prop을 사용하여 태그에서 Icon 삭제를 사용자 정의합니다. 기본값은 i-lucide-x입니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref(['Backlog', 'Todo'])
</script>
<template>
<UInputMenu v-model="value" multiple delete-icon="i-lucide-trash" :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref(['Backlog', 'Todo'])
</script>
<template>
<UInputMenu v-model="value" multiple delete-icon="i-lucide-trash" :items="items" />
</template>placeholder 자리 표시자
placeholder prop을 사용하여 자리 표시자 텍스트를 설정합니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
</script>
<template>
<UInputMenu placeholder="Select status" :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
</script>
<template>
<UInputMenu placeholder="Select status" :items="items" />
</template>Mode: badge{label="4.8+" class="align-text-top"} 모드
mode prop을 autocomplete로 설정하면 InputMenu를 제안이 포함된 자유 형식 텍스트 입력으로 변경합니다. modelValue는 선택된 항목이 아닌 입력 텍스트(string)가 됩니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('')
</script>
<template>
<UInputMenu
v-model="value"
mode="autocomplete"
:items="items"
:trailing-icon="false"
:content="{ hideWhenEmpty: true }"
placeholder="Type a status..."
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('')
</script>
<template>
<UInputMenu
v-model="value"
mode="autocomplete"
:items="items"
:trailing-icon="false"
:content="{ hideWhenEmpty: true }"
placeholder="Type a status..."
/>
</template>
mode가 autocomplete인 경우 multiple, by, resetSearchTermOnSelect 및 resetModelValueOnClear는 적용되지 않습니다.content.hideWhenEmpty prop를 사용하여 일치하는 제안이 없을 때 메뉴를 숨깁니다.Content 파일
content prop을 사용하여 InputMenu 내용이 렌더링되는 방식을 제어합니다. 예를 들어 align 또는 side와 같습니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu
v-model="value"
:content="{
align: 'center',
side: 'bottom',
sideOffset: 8
}"
:items="items"
/>
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu
v-model="value"
:content="{
align: 'center',
side: 'bottom',
sideOffset: 8
}"
:items="items"
/>
</template>Arrow 화살표
arrow prop를 사용하여 InputMenu에 화살표를 표시합니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" arrow :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" arrow :items="items" />
</template>color
InputMenu에 초점을 맞출 때 color Prop을 사용하여 링 색상을 변경합니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" color="neutral" highlight :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" color="neutral" highlight :items="items" />
</template>highlight prop은 초점 상태를 표시하기 위해 사용되며, 유효성 검사 오류가 발생할 때 내부적으로 사용됩니다.변형
variant prop 을 사용하여 InputMenu 의 변형을 변경합니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" color="neutral" variant="subtle" :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" color="neutral" variant="subtle" :items="items" />
</template>Size
size prop을 사용하여 InputMenu 크기를 변경합니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" size="xl" :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" size="xl" :items="items" />
</template>Icon 이미지
icon prop을 사용하여 InputMenu 내부에 Icon를 표시합니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" icon="i-lucide-search" size="md" :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" icon="i-lucide-search" size="md" :items="items" />
</template>트레일 아이콘
trailing-icon 소품을 사용하여 후행 Icon를 사용자 정의합니다. 기본값은 i-lucide-chevron-down입니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" trailing-icon="i-lucide-arrow-down" size="md" :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" trailing-icon="i-lucide-arrow-down" size="md" :items="items" />
</template>선택한 아이콘
selected-icon 소품을 사용하여 항목을 선택할 때 아이콘을 사용자 정의합니다. 기본값은 i-lucide-check입니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" selected-icon="i-lucide-flame" size="md" :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" selected-icon="i-lucide-flame" size="md" :items="items" />
</template>Clear : badge{label="4.4+" class="align-text-top"}
값을 선택할 때 clear Prop을 사용하여 지우기 버튼을 표시합니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" clear :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" clear :items="items" />
</template>지우기 아이콘: badge{label="4.4+" class="align-text-top"}
clear-icon 소품을 사용하여 지우기 단추 Icon를 사용자 정의합니다. 기본값은 i-lucide-x입니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" clear clear-icon="i-lucide-trash" :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" clear clear-icon="i-lucide-trash" :items="items" />
</template>Avatar (### 아바타)
avatar prop을 사용하여 InputMenu 내부에 Avatar를 표시합니다.
<script setup lang="ts">
const items = ref(['Nuxt', 'NuxtHub', 'NuxtLabs', 'Nuxt Modules', 'Nuxt Community'])
const value = ref('Nuxt')
</script>
<template>
<UInputMenu
v-model="value"
:avatar="{
src: 'https://github.com/nuxt.png',
loading: 'lazy'
}"
:items="items"
/>
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Nuxt', 'NuxtHub', 'NuxtLabs', 'Nuxt Modules', 'Nuxt Community'])
const value = ref('Nuxt')
</script>
<template>
<UInputMenu
v-model="value"
:avatar="{
src: 'https://github.com/nuxt.png',
loading: 'lazy'
}"
:items="items"
/>
</template>Loading 중
loading prop을 사용하여 InputMenu에 로드 아이콘을 표시합니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" loading :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" loading :items="items" />
</template>Loading 아이콘
loading-icon 소품을 사용하여 로드 아이콘을 사용자 정의합니다. 기본값은 i-lucide-loader-circle입니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" loading loading-icon="i-lucide-loader" :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" loading loading-icon="i-lucide-loader" :items="items" />
</template>비활성 화
disabled prop을 사용하여 InputMenu를 비활성화합니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
</script>
<template>
<UInputMenu disabled placeholder="Select status" :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
</script>
<template>
<UInputMenu disabled placeholder="Select status" :items="items" />
</template>examples 예제
With 아이템 타입
type 속성을 separator와 함께 사용하여 항목 사이의 구분 기호를 표시하거나 label를 사용하여 레이블을 표시할 수 있습니다.
<script setup lang="ts">
import type { InputMenuItem } from '@nuxt/ui'
const items = ref<InputMenuItem[]>([
[
{
type: 'label',
label: 'Fruits'
},
'Apple',
'Banana',
'Blueberry',
'Grapes',
'Pineapple'
],
[
{
type: 'label',
label: 'Vegetables'
},
'Aubergine',
'Broccoli',
'Carrot',
'Courgette',
'Leek'
]
])
const value = ref('Apple')
</script>
<template>
<UInputMenu v-model="value" :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
import type { InputMenuItem } from '@nuxt/ui'
const items = ref<InputMenuItem[]>([
[
{
type: 'label',
label: 'Fruits'
},
'Apple',
'Banana',
'Blueberry',
'Grapes',
'Pineapple'
],
[
{
type: 'label',
label: 'Vegetables'
},
'Aubergine',
'Broccoli',
'Carrot',
'Courgette',
'Leek'
]
])
const value = ref('Apple')
</script>
<template>
<UInputMenu v-model="value" :items="items" />
</template>label 항목을 그룹 제목으로 사용할 때 배열 배열을 전달하여 레이블이 그룹과 함께 필터링되도록 합니다.With 항목의 아이콘
icon 속성을 사용하여 항목 내부에 Icon를 표시할 수 있습니다.
<script setup lang="ts">
import type { InputMenuItem } from '@nuxt/ui'
const items = ref([
{
label: 'Backlog',
value: 'backlog',
icon: 'i-lucide-circle-help'
},
{
label: 'Todo',
value: 'todo',
icon: 'i-lucide-circle-plus'
},
{
label: 'In Progress',
value: 'in_progress',
icon: 'i-lucide-circle-arrow-up'
},
{
label: 'Done',
value: 'done',
icon: 'i-lucide-circle-check'
}
] satisfies InputMenuItem[])
const value = ref(items.value[0])
</script>
<template>
<UInputMenu v-model="value" :icon="value?.icon" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { InputMenuItem } from '@nuxt/ui'
const items = ref([
{
label: 'Backlog',
value: 'backlog',
icon: 'i-lucide-circle-help'
},
{
label: 'Todo',
value: 'todo',
icon: 'i-lucide-circle-plus'
},
{
label: 'In Progress',
value: 'in_progress',
icon: 'i-lucide-circle-arrow-up'
},
{
label: 'Done',
value: 'done',
icon: 'i-lucide-circle-check'
}
] satisfies InputMenuItem[])
const value = ref(items.value[0])
</script>
<template>
<UInputMenu v-model="value" :icon="value?.icon" :items="items" />
</template>
#leading 슬롯을 사용하여 선택된 아이콘을 표시할 수도 있습니다.항목에 아바타 포함
avatar 속성을 사용하여 Avatar를 항목 내부에 표시할 수 있습니다.
<script setup lang="ts">
import type { InputMenuItem } from '@nuxt/ui'
const items = ref([
{
label: 'benjamincanac',
value: 'benjamincanac',
avatar: {
src: 'https://github.com/benjamincanac.png',
alt: 'benjamincanac',
loading: 'lazy' as const
}
},
{
label: 'HugoRCD',
value: 'HugoRCD',
avatar: {
src: 'https://github.com/HugoRCD.png',
alt: 'HugoRCD',
loading: 'lazy' as const
}
},
{
label: 'atinux',
value: 'atinux',
avatar: {
src: 'https://github.com/atinux.png',
alt: 'atinux',
loading: 'lazy' as const
}
},
{
label: 'romhml',
value: 'romhml',
avatar: {
src: 'https://github.com/romhml.png',
alt: 'romhml',
loading: 'lazy' as const
}
}
] satisfies InputMenuItem[])
const value = ref(items.value[0])
</script>
<template>
<UInputMenu v-model="value" :avatar="value?.avatar" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { InputMenuItem } from '@nuxt/ui'
const items = ref([
{
label: 'benjamincanac',
value: 'benjamincanac',
avatar: {
src: 'https://github.com/benjamincanac.png',
alt: 'benjamincanac',
loading: 'lazy' as const
}
},
{
label: 'HugoRCD',
value: 'HugoRCD',
avatar: {
src: 'https://github.com/HugoRCD.png',
alt: 'HugoRCD',
loading: 'lazy' as const
}
},
{
label: 'atinux',
value: 'atinux',
avatar: {
src: 'https://github.com/atinux.png',
alt: 'atinux',
loading: 'lazy' as const
}
},
{
label: 'romhml',
value: 'romhml',
avatar: {
src: 'https://github.com/romhml.png',
alt: 'romhml',
loading: 'lazy' as const
}
}
] satisfies InputMenuItem[])
const value = ref(items.value[0])
</script>
<template>
<UInputMenu v-model="value" :avatar="value?.avatar" :items="items" />
</template>
#leading 슬롯을 사용하여 선택한 아바타를 표시할 수 있습니다.With 칩 in items
chip 속성을 사용하여 Chip를 항목 안에 표시할 수 있습니다.
<script setup lang="ts">
import type { InputMenuItem, ChipProps } from '@nuxt/ui'
const items = ref([
{
label: 'bug',
value: 'bug',
chip: {
color: 'error'
}
},
{
label: 'feature',
value: 'feature',
chip: {
color: 'success'
}
},
{
label: 'enhancement',
value: 'enhancement',
chip: {
color: 'info'
}
}
] satisfies InputMenuItem[])
const value = ref(items.value[0])
</script>
<template>
<UInputMenu v-model="value" :items="items">
<template #leading="{ modelValue, ui }">
<UChip
v-if="modelValue"
v-bind="modelValue.chip"
inset
standalone
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
:class="ui.itemLeadingChip()"
/>
</template>
</UInputMenu>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { InputMenuItem, ChipProps } from '@nuxt/ui'
const items = ref([
{
label: 'bug',
value: 'bug',
chip: {
color: 'error'
}
},
{
label: 'feature',
value: 'feature',
chip: {
color: 'success'
}
},
{
label: 'enhancement',
value: 'enhancement',
chip: {
color: 'info'
}
}
] satisfies InputMenuItem[])
const value = ref(items.value[0])
</script>
<template>
<UInputMenu v-model="value" :items="items">
<template #leading="{ modelValue, ui }">
<UChip
v-if="modelValue"
v-bind="modelValue.chip"
inset
standalone
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
:class="ui.itemLeadingChip()"
/>
</template>
</UInputMenu>
</template>
#leading 슬롯이 선택한 칩을 표시하는 데 사용됩니다.Control 오픈 상태
default-open prop 또는 v-model:open 지시문을 사용하여 개방 상태를 제어할 수 있습니다.
<script setup lang="ts">
const open = ref(false)
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
defineShortcuts({
o: () => open.value = !open.value
})
</script>
<template>
<UInputMenu v-model="value" v-model:open="open" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
const open = ref(false)
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
defineShortcuts({
o: () => open.value = !open.value
})
</script>
<template>
<UInputMenu v-model="value" v-model:open="open" :items="items" />
</template>
defineShortcuts를 사용하여 입력 메뉴를 토글할 수 있습니다. kbd{value="O"}를 누르면 됩니다.Control 포커스 시 열기 상태
입력에 초점을 맞추거나 클릭할 때 open-on-focus 또는 open-on-click 소품을 사용하여 메뉴를 열 수 있습니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const selected = ref('Backlog')
</script>
<template>
<UInputMenu
v-model="selected"
:items="items"
open-on-focus
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const selected = ref('Backlog')
</script>
<template>
<UInputMenu
v-model="selected"
:items="items"
open-on-focus
/>
</template>
Control 검색 항목
v-model:search-term 지시문을 사용하여 검색 용어를 제어합니다.
<script setup lang="ts">
const searchTerm = ref('D')
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" v-model:search-term="searchTerm" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
const searchTerm = ref('D')
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu v-model="value" v-model:search-term="searchTerm" :items="items" />
</template>
회전 아이콘 포함
다음은 InputMenu의 열린 상태를 나타내는 회전 아이콘이 있는 예입니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu
v-model="value"
:items="items"
:ui="{
trailingIcon: 'group-data-[state=open]:rotate-180 transition-transform duration-200'
}"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>
<template>
<UInputMenu
v-model="value"
:items="items"
:ui="{
trailingIcon: 'group-data-[state=open]:rotate-180 transition-transform duration-200'
}"
/>
</template>
프로젝트 만들기
create-item prop을 사용하여 사용자가 미리 정의된 옵션에 없는 사용자 정의 값을 추가할 수 있도록 합니다.
<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
function onCreate(item: string) {
items.value.push(item)
value.value = item
}
</script>
<template>
<UInputMenu
v-model="value"
create-item
:items="items"
class="w-48"
@create="onCreate"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
function onCreate(item: string) {
items.value.push(item)
value.value = item
}
</script>
<template>
<UInputMenu
v-model="value"
create-item
:items="items"
class="w-48"
@create="onCreate"
/>
</template>
always로 설정하십시오.가져온 항목과 함께
API에서 항목을 가져와서 InputMenu에서 사용할 수 있습니다.You can fetch items from an API and use them in the InputMenu.
<script setup lang="ts">
import type { AvatarProps } from '@nuxt/ui'
const { data: users, status, execute } = await useLazyFetch('https://jsonplaceholder.typicode.com/users', {
key: 'typicode-users',
transform: (data: { id: number, name: string }[]) => {
return data?.map(user => ({
label: user.name,
value: String(user.id),
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, loading: 'lazy' as const }
}))
},
immediate: false
})
function onOpen() {
if (!users.value?.length) {
execute()
}
}
</script>
<template>
<UInputMenu
:items="users"
:loading="status === 'pending'"
icon="i-lucide-user"
placeholder="Select user"
@update:open="onOpen"
>
<template #leading="{ modelValue, ui }">
<UAvatar
v-if="modelValue"
v-bind="modelValue.avatar"
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
:class="ui.leadingAvatar()"
/>
</template>
</UInputMenu>
</template>
useLazyFetch와 immediate: false를 사용하여 메뉴가 열릴 때만 데이터를 가져오므로 페이지 로드 시 불필요한 API 호출을 피할 수 있습니다.무시 필터 사용
ignore-filter prop을 true로 설정하여 내부 검색을 비활성화하고 자체 검색 논리를 사용합니다.
<script setup lang="ts">
import { refDebounced } from '@vueuse/core'
import type { AvatarProps } from '@nuxt/ui'
const searchTerm = ref('')
const searchTermDebounced = refDebounced(searchTerm, 200)
const { data: users, status, execute } = await useLazyFetch('https://jsonplaceholder.typicode.com/users', {
key: 'input-menu-users-search',
params: { q: searchTermDebounced },
transform: (data: { id: number, name: string }[]) => {
return data?.map(user => ({
label: user.name,
value: String(user.id),
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, loading: 'lazy' as const }
}))
},
immediate: false
})
function onOpen() {
if (!users.value?.length) {
execute()
}
}
</script>
<template>
<UInputMenu
v-model:search-term="searchTerm"
:items="users"
:loading="status === 'pending'"
ignore-filter
icon="i-lucide-user"
placeholder="Select user"
@update:open="onOpen"
>
<template #leading="{ modelValue, ui }">
<UAvatar
v-if="modelValue"
v-bind="modelValue.avatar"
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
:class="ui.leadingAvatar()"
/>
</template>
</UInputMenu>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { refDebounced } from '@vueuse/core'
import type { AvatarProps } from '@nuxt/ui'
const searchTerm = ref('')
const searchTermDebounced = refDebounced(searchTerm, 200)
const { data: users, status, execute } = await useLazyFetch('https://jsonplaceholder.typicode.com/users', {
key: 'input-menu-users-search',
params: { q: searchTermDebounced },
transform: (data: { id: number, name: string }[]) => {
return data?.map(user => ({
label: user.name,
value: String(user.id),
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, loading: 'lazy' as const }
}))
},
immediate: false
})
function onOpen() {
if (!users.value?.length) {
execute()
}
}
</script>
<template>
<UInputMenu
v-model:search-term="searchTerm"
:items="users"
:loading="status === 'pending'"
ignore-filter
icon="i-lucide-user"
placeholder="Select user"
@update:open="onOpen"
>
<template #leading="{ modelValue, ui }">
<UAvatar
v-if="modelValue"
v-bind="modelValue.avatar"
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
:class="ui.leadingAvatar()"
/>
</template>
</UInputMenu>
</template>
refDebounced를 사용하여 API 호출을 토론합니다. 검색은 immediate: false를 사용하여 지연되므로 메뉴가 열릴 때까지 요청이 수행되지 않습니다.With 필터 필드
filter-fields Prop을 필드 배열과 함께 사용하여 필터링합니다. 기본값은 [labelKey]입니다.
<script setup lang="ts">
import type { AvatarProps } from '@nuxt/ui'
const { data: users, status, execute } = await useLazyFetch('https://jsonplaceholder.typicode.com/users', {
key: 'typicode-users-email',
transform: (data: { id: number, name: string, email: string }[]) => {
return data?.map(user => ({
label: user.name,
email: user.email,
value: String(user.id),
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, loading: 'lazy' as const }
}))
},
immediate: false
})
function onOpen() {
if (!users.value?.length) {
execute()
}
}
</script>
<template>
<UInputMenu
:items="users"
:loading="status === 'pending'"
:filter-fields="['label', 'email']"
icon="i-lucide-user"
placeholder="Select user"
class="w-80"
@update:open="onOpen"
>
<template #leading="{ modelValue, ui }">
<UAvatar
v-if="modelValue"
v-bind="modelValue.avatar"
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
:class="ui.leadingAvatar()"
/>
</template>
<template #item-label="{ item }">
{{ item.label }}
<span class="text-muted">
{{ item.email }}
</span>
</template>
</UInputMenu>
</template>
useLazyFetch와 immediate: false를 사용하여 메뉴가 열릴 때만 데이터를 가져오므로 페이지 로드 시 불필요한 API 호출을 피할 수 있습니다.가상화 지원: badge{label="4.1+" class="align-text-top"}
virtualize prop을 사용하여 큰 목록에 대해 부울 또는 { estimateSize: 32, overscan: 12 }와 같은 옵션이있는 개체로 가상화를 활성화합니다.
<script setup lang="ts">
import type { InputMenuItem } from '@nuxt/ui'
const items: InputMenuItem[] = Array(1000)
.fill(0)
.map((_, i) => ({
label: `item-${i}`,
value: i
}))
</script>
<template>
<UInputMenu virtualize :items="items" class="w-48" />
</template>무한 스크롤 사용: badge{label="4.4+" class="align-text-top"}
useInfiniteScroll 컴포지블을 사용하여 사용자가 스크롤할 때 더 많은 데이터를 로드할 수 있습니다.
<script setup lang="ts">
import { useInfiniteScroll } from '@vueuse/core'
type User = {
firstName: string
}
type UserResponse = {
users: User[]
total: number
skip: number
limit: number
}
const skip = ref(0)
const { data, status, execute } = await useLazyFetch(
'https://dummyjson.com/users?limit=10&select=firstName',
{
key: 'input-menu-users-infinite-scroll',
params: { skip },
transform: (data?: UserResponse) => {
return data?.users.map((user) => user.firstName)
},
immediate: false
}
)
const users = ref<string[]>([])
watch(data, () => {
users.value = [...users.value, ...(data.value || [])]
})
function onOpen() {
if (!users.value?.length) {
execute()
}
}
const inputMenu = useTemplateRef('inputMenu')
onMounted(() => {
useInfiniteScroll(
() => inputMenu.value?.viewportRef,
() => {
skip.value += 10
},
{
canLoadMore: () => {
return status.value !== 'pending'
}
}
)
})
</script>
<template>
<UInputMenu ref="inputMenu" placeholder="Select user" :items="users" @update:open="onOpen" />
</template><script setup lang="ts">
import { ref, watch, onMounted, useTemplateRef } from 'vue'
import { useInfiniteScroll } from '@vueuse/core'
type User = {
firstName: string
}
type UserResponse = {
users: User[]
total: number
skip: number
limit: number
}
const skip = ref(0)
const { data, status, execute } = await useLazyFetch(
'https://dummyjson.com/users?limit=10&select=firstName',
{
key: 'input-menu-users-infinite-scroll',
params: { skip },
transform: (data?: UserResponse) => {
return data?.users.map((user) => user.firstName)
},
immediate: false
}
)
const users = ref<string[]>([])
watch(data, () => {
users.value = [...users.value, ...(data.value || [])]
})
function onOpen() {
if (!users.value?.length) {
execute()
}
}
const inputMenu = useTemplateRef('inputMenu')
onMounted(() => {
useInfiniteScroll(
() => inputMenu.value?.viewportRef,
() => {
skip.value += 10
},
{
canLoadMore: () => {
return status.value !== 'pending'
}
}
)
})
</script>
<template>
<UInputMenu ref="inputMenu" placeholder="Select user" :items="users" @update:open="onOpen" />
</template>useLazyFetch를 immediate: false와 함께 사용하므로 사용자가 스크롤할 때만 데이터가 로드됩니다.With full content width 전체 콘텐츠 너비
ui.content 슬롯에 min-w-fit 클래스를 추가하여 내용을 항목의 전체 너비로 확장할 수 있습니다.
<script setup lang="ts">
const { data: users, execute } = await useLazyFetch('https://jsonplaceholder.typicode.com/users', {
key: 'typicode-users-email',
transform: (data: { id: number, name: string, email: string }[]) => {
return data?.map(user => ({
label: user.name,
email: user.email,
value: String(user.id),
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, loading: 'lazy' as const }
}))
},
immediate: false
})
function onOpen() {
if (!users.value?.length) {
execute()
}
}
</script>
<template>
<UInputMenu
:items="users"
icon="i-lucide-user"
placeholder="Select user"
:ui="{ content: 'min-w-fit' }"
@update:open="onOpen"
>
<template #item-label="{ item }">
{{ item.label }}
<span class="text-muted">
{{ item.email }}
</span>
</template>
</UInputMenu>
</template>
app.config.ts에서 전체적으로 콘텐츠 너비를 변경할 수 있습니다.export default defineAppConfig({
ui: {
inputMenu: {
slots: {
content: 'min-w-fit'
}
}
}
})
As a country 선택기
입력 메뉴를 로드가 느린 국가 선택기로 사용할 수 있습니다. 국가는 메뉴를 처음 열었을 때만 가져오기됩니다.
<script setup lang="ts">
const { data: countries, status, execute } = await useLazyFetch<{
name: string
code: string
emoji: string
}[]>('/api/countries.json', {
key: 'api-countries',
immediate: false
})
function onOpen() {
if (!countries.value?.length) {
execute()
}
}
</script>
<template>
<UInputMenu
:items="countries"
:loading="status === 'pending'"
label-key="name"
:search-input="{ icon: 'i-lucide-search' }"
placeholder="Select country"
class="w-48"
@update:open="onOpen"
>
<template #leading="{ modelValue, ui }">
<span v-if="modelValue" class="size-5 text-center">
{{ modelValue?.emoji }}
</span>
<UIcon v-else name="i-lucide-earth" :class="ui.leadingIcon()" />
</template>
<template #item-leading="{ item }">
<span class="size-5 text-center">
{{ item.emoji }}
</span>
</template>
</UInputMenu>
</template>
useLazyFetch와 immediate: false를 사용하여 메뉴를 처음 열었을 때 국가만 로드합니다.API
Props (### Props)
| Prop | Default | Type |
|---|---|---|
as | 'div' | anyThe element or component this component should render as. |
id | string | |
type | 'text' | "number" | "search" | "color" | "button" | "checkbox" | "date" | "datetime-local" | "email" | "file" | "hidden" | "image" | "month" | "password" | "radio" | "range" | "reset" | "submit" | "tel" | "text" | "time" | "url" | "week" | string |
placeholder | stringThe placeholder text when the input is empty. | |
color | 'primary' | "primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral" |
variant | 'outline' | "soft" | "outline" | "subtle" | "ghost" | "none" |
size | 'md' | "sm" | "md" | "xs" | "lg" | "xl" |
required | boolean | |
autofocus | boolean | |
autofocusDelay | 0 | number |
trailingIcon | appConfig.ui.icons.chevronDown | anyThe icon displayed to open the menu. |
selectedIcon | appConfig.ui.icons.check | anyThe icon displayed when an item is selected. |
deleteIcon | appConfig.ui.icons.close | anyThe icon displayed to delete a tag.
Works only when |
clear | false | C & false | C & true | C & Partial<Omit<ButtonProps, LinkPropsKeys>>Display a clear button to reset the model value. Can be an object to pass additional props to the Button. |
clearIcon | appConfig.ui.icons.close | anyThe icon displayed in the clear button. |
content | { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' } | ComboboxContentProps & Partial<EmitsToProps<DismissableLayerEmits>>The content of the menu. |
arrow | false | boolean | ComboboxArrowProps Display an arrow alongside the menu.
|
portal | true | string | false | true | HTMLElementRender the menu in a portal. |
virtualize | false | boolean | { overscan?: number ; estimateSize?: number | ((index: number) => number) | undefined; } | undefinedEnable virtualization for large lists. Note: when enabled, all groups are flattened into a single list due to a limitation of Reka UI (https://github.com/unovue/reka-ui/issues/1885). |
valueKey | undefined | VKWhen |
labelKey | 'label' | keyof Extract<NestedItem<T>, object> & string | DotPathKeys<Extract<NestedItem<T>, object>>When |
descriptionKey | 'description' | keyof Extract<NestedItem<T>, object> & string | DotPathKeys<Extract<NestedItem<T>, object>>When |
items | T | |
defaultValue | _Number<_Optional<_Nullable<GetModelValue<T, VK, M, ExcludeItem>, Mod>, Mod>, Mod> | IsClearUsed<M, C>The value of the InputMenu when initially rendered. Use when you do not need to control the state of the InputMenu. | |
modelValue | _Number<_Optional<_Nullable<GetModelValue<T, VK, M, ExcludeItem>, Mod>, Mod>, Mod> | IsClearUsed<M, C>The controlled value of the InputMenu. Can be binded-with with | |
modelModifiers | Mod | |
multiple | MWhether multiple options can be selected or not. | |
highlight | boolean Highlight the ring color like a focus state. | |
fixed | boolean Keep the mobile text size on all breakpoints. | |
mode | 'combobox' | "autocomplete" | "combobox"The behavior of the InputMenu.
|
createItem | false | boolean | "always" | { position?: "bottom" | "top" ; when?: "empty" | "always" | undefined; } | undefinedDetermines if custom user input that does not exist in options can be added. |
filterFields | [labelKey] | string[]Fields to filter items by. |
ignoreFilter | false | boolean When |
disabled | boolean When | |
open | boolean The controlled open state of the Combobox. Can be binded with | |
defaultOpen | boolean The open state of the combobox when it is initially rendered. | |
name | stringThe name of the field. Submitted with its owning form as part of a name/value pair. | |
resetSearchTermOnBlur | true | boolean Whether to reset the searchTerm when the Combobox input blurred |
resetSearchTermOnSelect | true | boolean Whether to reset the searchTerm when the Combobox value is selected |
resetModelValueOnClear | true | boolean When |
highlightOnHover | boolean When | |
openOnClick | `false` | boolean Whether to open the combobox when the input is clicked |
openOnFocus | `false` | boolean Whether to open the combobox when the input is focused |
by | string | (a: T, b: T): booleanUse this to compare objects by a particular field, or pass your own comparison function for complete control over how objects are compared. | |
icon | anyDisplay an icon based on the | |
avatar | AvatarPropsDisplay an avatar on the left side. | |
leading | boolean When | |
leadingIcon | anyDisplay an icon on the left side. | |
trailing | boolean When | |
loading | boolean When | |
loadingIcon | appConfig.ui.icons.loading | anyThe icon when the |
list | string | |
readonly | false | true | "true" | "false" | |
autocomplete | string | "on" | "off" | |
searchTerm | '' | string |
ui | { root?: SlotClass; base?: SlotClass; leading?: SlotClass; leadingIcon?: SlotClass; leadingAvatar?: SlotClass; leadingAvatarSize?: SlotClass; trailing?: SlotClass; trailingIcon?: SlotClass; trailingClear?: SlotClass; arrow?: SlotClass; content?: SlotClass; viewport?: SlotClass; group?: SlotClass; empty?: SlotClass; label?: SlotClass; separator?: SlotClass; item?: SlotClass; itemLeadingIcon?: SlotClass; itemLeadingAvatar?: SlotClass; itemLeadingAvatarSize?: SlotClass; itemLeadingChip?: SlotClass; itemLeadingChipSize?: SlotClass; itemTrailing?: SlotClass; itemTrailingIcon?: SlotClass; itemWrapper?: SlotClass; itemLabel?: SlotClass; itemDescription?: SlotClass; tagsItem?: SlotClass; tagsItemText?: SlotClass; tagsItemDelete?: SlotClass; tagsItemDeleteIcon?: SlotClass; tagsInput?: SlotClass; } |
Slots
| Slot | Type |
|---|---|
leading | { modelValue: _Number<_Optional<_Nullable<GetModelValue<T, VK, M, ExcludeItem>, Mod>, Mod>, Mod> | IsClearUsed<M, C>; open: boolean; ui: object; } |
trailing | { modelValue: _Number<_Optional<_Nullable<GetModelValue<T, VK, M, ExcludeItem>, Mod>, Mod>, Mod> | IsClearUsed<M, C>; open: boolean; ui: object; } |
empty | { searchTerm: string; } |
item | { item: NestedItem<T>; index: number; ui: object; } |
item-leading | { item: NestedItem<T>; index: number; ui: object; } |
item-label | { item: NestedItem<T>; index: number; } |
item-description | { item: NestedItem<T>; index: number; } |
item-trailing | { item: NestedItem<T>; index: number; ui: object; } |
tags-item-text | { item: NestedItem<T>; index: number; } |
tags-item-delete | { item: NestedItem<T>; index: number; ui: object; } |
content-top | {} |
content-bottom | {} |
create-item-label | { item: string; } |
Emits 이미지
| Event | Type |
|---|---|
update:open | [value: boolean] |
change | [event: Event] |
blur | [event: FocusEvent] |
focus | [event: FocusEvent] |
create | [item: string] |
clear | [] |
highlight | [payload: { ref: HTMLElement; value: _Number<_Optional<_Nullable<GetModelValue<T, VK, M, ExcludeItem>, Mod>, Mod>, Mod> | IsClearUsed<M, C>; } | undefined] |
remove-tag | [item: _Number<_Optional<_Nullable<GetModelValue<T, VK, M, ExcludeItem>, Mod>, Mod>, Mod> | IsClearUsed<M, C>] |
update:modelValue | [value: _Number<_Optional<_Nullable<GetModelValue<T, VK, M, ExcludeItem>, Mod>, Mod>, Mod> | IsClearUsed<M, C>] |
update:searchTerm | [value: string] |
노출
템플릿 참조를 통해 컴포넌트에 액세스하는 경우 다음을 사용할 수 있습니다.
| 이름 (Name) | 유형 (Type) |
|---|---|
inputRef의 발음을 {lang="ts-type"} | Ref<HTMLInputElement | null>의 발음을 Ref<HTMLInputElement | null>xph787 |
viewportRef의 발음을 viewportRefxph790 | Ref<HTMLDivElement | null> (Ref<HTMLDivElement | null>) |
Theme (## 테마)
export default defineAppConfig({
ui: {
inputMenu: {
slots: {
root: 'relative inline-flex items-center',
base: [
'rounded-md',
'transition-colors'
],
leading: 'absolute inset-y-0 start-0 flex items-center',
leadingIcon: 'shrink-0 text-dimmed',
leadingAvatar: 'shrink-0',
leadingAvatarSize: '',
trailing: 'group absolute inset-y-0 end-0 flex items-center disabled:cursor-not-allowed disabled:opacity-75 focus:outline-none',
trailingIcon: 'shrink-0 text-dimmed',
trailingClear: 'p-0',
arrow: 'fill-bg stroke-default',
content: 'max-h-[min(15rem,var(--reka-combobox-content-available-height,15rem))] w-(--reka-combobox-trigger-width) bg-default shadow-lg rounded-md ring ring-default overflow-hidden data-[state=open]:animate-[scale-in_100ms_var(--ease-out)] data-[state=closed]:animate-[scale-out_100ms_var(--ease-out)] origin-(--reka-combobox-content-transform-origin) pointer-events-auto flex flex-col',
viewport: 'relative scroll-py-1 overflow-y-auto flex-1',
group: 'p-1 isolate',
empty: 'text-center text-muted',
label: 'font-semibold text-highlighted',
separator: '-mx-1 my-1 h-px bg-border',
item: [
'group relative w-full flex items-start gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50',
'transition-colors before:transition-colors'
],
itemLeadingIcon: [
'shrink-0 text-dimmed group-data-highlighted:not-group-data-disabled:text-default',
'transition-colors'
],
itemLeadingAvatar: 'shrink-0',
itemLeadingAvatarSize: '',
itemLeadingChip: 'shrink-0',
itemLeadingChipSize: '',
itemTrailing: 'ms-auto inline-flex gap-1.5 items-center',
itemTrailingIcon: 'shrink-0',
itemWrapper: 'flex-1 flex flex-col min-w-0',
itemLabel: 'truncate',
itemDescription: 'truncate text-muted',
tagsItem: 'px-1.5 py-0.5 rounded-sm font-medium inline-flex items-center gap-0.5 ring ring-inset ring-accented bg-elevated text-default data-disabled:cursor-not-allowed data-disabled:opacity-75',
tagsItemText: 'truncate',
tagsItemDelete: [
'inline-flex items-center rounded-xs text-dimmed hover:text-default hover:bg-accented/75 disabled:pointer-events-none',
'transition-colors'
],
tagsItemDeleteIcon: 'shrink-0',
tagsInput: 'flex-1 border-0 bg-transparent placeholder:text-dimmed focus:outline-none disabled:cursor-not-allowed disabled:opacity-75'
},
variants: {
fieldGroup: {
horizontal: {
root: 'group has-focus-visible:z-[1]'
},
vertical: {
root: 'group has-focus-visible:z-[1]'
}
},
size: {
xs: {
base: 'px-2 py-1 text-sm/4 gap-1',
leading: 'ps-2',
trailing: 'pe-2',
leadingIcon: 'size-4',
leadingAvatarSize: '3xs',
trailingIcon: 'size-4',
label: 'p-1 text-[10px]/3 gap-1',
item: 'p-1 text-xs gap-1',
itemLeadingIcon: 'size-4',
itemLeadingAvatarSize: '3xs',
itemLeadingChip: 'size-4',
itemLeadingChipSize: 'sm',
itemTrailingIcon: 'size-4',
tagsItem: 'text-[10px]/3',
tagsItemDeleteIcon: 'size-3',
empty: 'p-2 text-xs'
},
sm: {
base: 'px-2.5 py-1.5 text-sm/4 gap-1.5',
leading: 'ps-2.5',
trailing: 'pe-2.5',
leadingIcon: 'size-4',
leadingAvatarSize: '3xs',
trailingIcon: 'size-4',
label: 'p-1.5 text-[10px]/3 gap-1.5',
item: 'p-1.5 text-xs gap-1.5',
itemLeadingIcon: 'size-4',
itemLeadingAvatarSize: '3xs',
itemLeadingChip: 'size-4',
itemLeadingChipSize: 'sm',
itemTrailingIcon: 'size-4',
tagsItem: 'text-[10px]/3',
tagsItemDeleteIcon: 'size-3',
empty: 'p-2.5 text-xs'
},
md: {
base: 'px-2.5 py-1.5 text-base/5 gap-1.5',
leading: 'ps-2.5',
trailing: 'pe-2.5',
leadingIcon: 'size-5',
leadingAvatarSize: '2xs',
trailingIcon: 'size-5',
label: 'p-1.5 text-xs gap-1.5',
item: 'p-1.5 text-sm gap-1.5',
itemLeadingIcon: 'size-5',
itemLeadingAvatarSize: '2xs',
itemLeadingChip: 'size-5',
itemLeadingChipSize: 'md',
itemTrailingIcon: 'size-5',
tagsItem: 'text-xs',
tagsItemDeleteIcon: 'size-3.5',
empty: 'p-2.5 text-sm'
},
lg: {
base: 'px-3 py-2 text-base/5 gap-2',
leading: 'ps-3',
trailing: 'pe-3',
leadingIcon: 'size-5',
leadingAvatarSize: '2xs',
trailingIcon: 'size-5',
label: 'p-2 text-xs gap-2',
item: 'p-2 text-sm gap-2',
itemLeadingIcon: 'size-5',
itemLeadingAvatarSize: '2xs',
itemLeadingChip: 'size-5',
itemLeadingChipSize: 'md',
itemTrailingIcon: 'size-5',
tagsItem: 'text-xs',
tagsItemDeleteIcon: 'size-3.5',
empty: 'p-3 text-sm'
},
xl: {
base: 'px-3 py-2 text-base gap-2',
leading: 'ps-3',
trailing: 'pe-3',
leadingIcon: 'size-6',
leadingAvatarSize: 'xs',
trailingIcon: 'size-6',
label: 'p-2 text-sm gap-2',
item: 'p-2 text-base gap-2',
itemLeadingIcon: 'size-6',
itemLeadingAvatarSize: 'xs',
itemLeadingChip: 'size-6',
itemLeadingChipSize: 'lg',
itemTrailingIcon: 'size-6',
tagsItem: 'text-sm',
tagsItemDeleteIcon: 'size-4',
empty: 'p-3 text-base'
}
},
variant: {
outline: 'text-highlighted bg-default ring ring-inset ring-accented',
soft: 'text-highlighted bg-elevated/50 hover:bg-elevated focus:bg-elevated disabled:bg-elevated/50',
subtle: 'text-highlighted bg-elevated ring ring-inset ring-accented',
ghost: 'text-highlighted bg-transparent hover:bg-elevated focus:bg-elevated disabled:bg-transparent dark:disabled:bg-transparent',
none: 'text-highlighted bg-transparent focus:outline-none'
},
color: {
primary: '',
secondary: '',
success: '',
info: '',
warning: '',
error: '',
neutral: ''
},
leading: {
true: ''
},
trailing: {
true: ''
},
loading: {
true: ''
},
highlight: {
true: ''
},
fixed: {
false: ''
},
type: {
file: 'file:me-1.5 file:font-medium file:text-muted file:outline-none'
},
virtualize: {
true: {
viewport: 'p-1 isolate'
},
false: {
viewport: 'divide-y divide-default'
}
},
multiple: {
true: {
root: 'flex-wrap'
},
false: {
base: 'w-full border-0 placeholder:text-dimmed disabled:cursor-not-allowed disabled:opacity-75'
}
}
},
compoundVariants: [
{
multiple: false,
fieldGroup: 'horizontal',
class: {
base: 'group-not-only:group-first:rounded-e-none group-not-only:group-last:rounded-s-none group-not-last:group-not-first:rounded-none'
}
},
{
multiple: false,
fieldGroup: 'vertical',
class: {
base: 'group-not-only:group-first:rounded-b-none group-not-only:group-last:rounded-t-none group-not-last:group-not-first:rounded-none'
}
},
{
multiple: true,
fieldGroup: 'horizontal',
class: {
base: 'not-only:first:rounded-e-none not-only:last:rounded-s-none not-last:not-first:rounded-none focus-visible:z-[1]'
}
},
{
multiple: true,
fieldGroup: 'vertical',
class: {
base: 'not-only:first:rounded-b-none not-only:last:rounded-t-none not-last:not-first:rounded-none focus-visible:z-[1]'
}
},
{
variant: 'soft',
multiple: true,
class: 'has-focus:bg-elevated has-focus-visible:outline-3'
},
{
variant: 'ghost',
multiple: true,
class: 'has-focus:bg-elevated has-focus-visible:outline-3'
},
{
color: 'primary',
multiple: true,
variant: [
'outline',
'subtle'
],
class: 'has-focus-visible:outline-3 has-focus-visible:ring-primary'
},
{
color: 'neutral',
multiple: true,
variant: [
'outline',
'subtle'
],
class: 'has-focus-visible:outline-3 has-focus-visible:ring-inverted'
},
{
color: 'primary',
variant: [
'outline',
'subtle'
],
class: 'outline-primary/25 focus-visible:outline-3 focus-visible:ring-primary'
},
{
color: 'primary',
variant: [
'soft',
'ghost'
],
class: 'outline-primary/25 focus-visible:outline-3'
},
{
color: 'primary',
highlight: true,
class: 'ring ring-inset ring-primary'
},
{
color: 'neutral',
variant: [
'outline',
'subtle'
],
class: 'outline-inverted/25 focus-visible:outline-3 focus-visible:ring-inverted'
},
{
color: 'neutral',
variant: [
'soft',
'ghost'
],
class: 'outline-inverted/25 focus-visible:outline-3'
},
{
color: 'neutral',
highlight: true,
class: 'ring ring-inset ring-inverted'
},
{
leading: true,
size: 'xs',
class: 'ps-7'
},
{
leading: true,
size: 'sm',
class: 'ps-8'
},
{
leading: true,
size: 'md',
class: 'ps-9'
},
{
leading: true,
size: 'lg',
class: 'ps-10'
},
{
leading: true,
size: 'xl',
class: 'ps-11'
},
{
trailing: true,
size: 'xs',
class: 'pe-7'
},
{
trailing: true,
size: 'sm',
class: 'pe-8'
},
{
trailing: true,
size: 'md',
class: 'pe-9'
},
{
trailing: true,
size: 'lg',
class: 'pe-10'
},
{
trailing: true,
size: 'xl',
class: 'pe-11'
},
{
loading: true,
leading: true,
class: {
leadingIcon: 'animate-spin'
}
},
{
loading: true,
leading: false,
trailing: true,
class: {
trailingIcon: 'animate-spin'
}
},
{
fixed: false,
size: 'xs',
class: 'md:text-xs'
},
{
fixed: false,
size: 'sm',
class: 'md:text-xs'
},
{
fixed: false,
size: 'md',
class: 'md:text-sm'
},
{
fixed: false,
size: 'lg',
class: 'md:text-sm'
}
],
defaultVariants: {
size: 'md',
color: 'primary',
variant: 'outline'
}
}
}
})import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
ui: {
inputMenu: {
slots: {
root: 'relative inline-flex items-center',
base: [
'rounded-md',
'transition-colors'
],
leading: 'absolute inset-y-0 start-0 flex items-center',
leadingIcon: 'shrink-0 text-dimmed',
leadingAvatar: 'shrink-0',
leadingAvatarSize: '',
trailing: 'group absolute inset-y-0 end-0 flex items-center disabled:cursor-not-allowed disabled:opacity-75 focus:outline-none',
trailingIcon: 'shrink-0 text-dimmed',
trailingClear: 'p-0',
arrow: 'fill-bg stroke-default',
content: 'max-h-[min(15rem,var(--reka-combobox-content-available-height,15rem))] w-(--reka-combobox-trigger-width) bg-default shadow-lg rounded-md ring ring-default overflow-hidden data-[state=open]:animate-[scale-in_100ms_var(--ease-out)] data-[state=closed]:animate-[scale-out_100ms_var(--ease-out)] origin-(--reka-combobox-content-transform-origin) pointer-events-auto flex flex-col',
viewport: 'relative scroll-py-1 overflow-y-auto flex-1',
group: 'p-1 isolate',
empty: 'text-center text-muted',
label: 'font-semibold text-highlighted',
separator: '-mx-1 my-1 h-px bg-border',
item: [
'group relative w-full flex items-start gap-1.5 p-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50',
'transition-colors before:transition-colors'
],
itemLeadingIcon: [
'shrink-0 text-dimmed group-data-highlighted:not-group-data-disabled:text-default',
'transition-colors'
],
itemLeadingAvatar: 'shrink-0',
itemLeadingAvatarSize: '',
itemLeadingChip: 'shrink-0',
itemLeadingChipSize: '',
itemTrailing: 'ms-auto inline-flex gap-1.5 items-center',
itemTrailingIcon: 'shrink-0',
itemWrapper: 'flex-1 flex flex-col min-w-0',
itemLabel: 'truncate',
itemDescription: 'truncate text-muted',
tagsItem: 'px-1.5 py-0.5 rounded-sm font-medium inline-flex items-center gap-0.5 ring ring-inset ring-accented bg-elevated text-default data-disabled:cursor-not-allowed data-disabled:opacity-75',
tagsItemText: 'truncate',
tagsItemDelete: [
'inline-flex items-center rounded-xs text-dimmed hover:text-default hover:bg-accented/75 disabled:pointer-events-none',
'transition-colors'
],
tagsItemDeleteIcon: 'shrink-0',
tagsInput: 'flex-1 border-0 bg-transparent placeholder:text-dimmed focus:outline-none disabled:cursor-not-allowed disabled:opacity-75'
},
variants: {
fieldGroup: {
horizontal: {
root: 'group has-focus-visible:z-[1]'
},
vertical: {
root: 'group has-focus-visible:z-[1]'
}
},
size: {
xs: {
base: 'px-2 py-1 text-sm/4 gap-1',
leading: 'ps-2',
trailing: 'pe-2',
leadingIcon: 'size-4',
leadingAvatarSize: '3xs',
trailingIcon: 'size-4',
label: 'p-1 text-[10px]/3 gap-1',
item: 'p-1 text-xs gap-1',
itemLeadingIcon: 'size-4',
itemLeadingAvatarSize: '3xs',
itemLeadingChip: 'size-4',
itemLeadingChipSize: 'sm',
itemTrailingIcon: 'size-4',
tagsItem: 'text-[10px]/3',
tagsItemDeleteIcon: 'size-3',
empty: 'p-2 text-xs'
},
sm: {
base: 'px-2.5 py-1.5 text-sm/4 gap-1.5',
leading: 'ps-2.5',
trailing: 'pe-2.5',
leadingIcon: 'size-4',
leadingAvatarSize: '3xs',
trailingIcon: 'size-4',
label: 'p-1.5 text-[10px]/3 gap-1.5',
item: 'p-1.5 text-xs gap-1.5',
itemLeadingIcon: 'size-4',
itemLeadingAvatarSize: '3xs',
itemLeadingChip: 'size-4',
itemLeadingChipSize: 'sm',
itemTrailingIcon: 'size-4',
tagsItem: 'text-[10px]/3',
tagsItemDeleteIcon: 'size-3',
empty: 'p-2.5 text-xs'
},
md: {
base: 'px-2.5 py-1.5 text-base/5 gap-1.5',
leading: 'ps-2.5',
trailing: 'pe-2.5',
leadingIcon: 'size-5',
leadingAvatarSize: '2xs',
trailingIcon: 'size-5',
label: 'p-1.5 text-xs gap-1.5',
item: 'p-1.5 text-sm gap-1.5',
itemLeadingIcon: 'size-5',
itemLeadingAvatarSize: '2xs',
itemLeadingChip: 'size-5',
itemLeadingChipSize: 'md',
itemTrailingIcon: 'size-5',
tagsItem: 'text-xs',
tagsItemDeleteIcon: 'size-3.5',
empty: 'p-2.5 text-sm'
},
lg: {
base: 'px-3 py-2 text-base/5 gap-2',
leading: 'ps-3',
trailing: 'pe-3',
leadingIcon: 'size-5',
leadingAvatarSize: '2xs',
trailingIcon: 'size-5',
label: 'p-2 text-xs gap-2',
item: 'p-2 text-sm gap-2',
itemLeadingIcon: 'size-5',
itemLeadingAvatarSize: '2xs',
itemLeadingChip: 'size-5',
itemLeadingChipSize: 'md',
itemTrailingIcon: 'size-5',
tagsItem: 'text-xs',
tagsItemDeleteIcon: 'size-3.5',
empty: 'p-3 text-sm'
},
xl: {
base: 'px-3 py-2 text-base gap-2',
leading: 'ps-3',
trailing: 'pe-3',
leadingIcon: 'size-6',
leadingAvatarSize: 'xs',
trailingIcon: 'size-6',
label: 'p-2 text-sm gap-2',
item: 'p-2 text-base gap-2',
itemLeadingIcon: 'size-6',
itemLeadingAvatarSize: 'xs',
itemLeadingChip: 'size-6',
itemLeadingChipSize: 'lg',
itemTrailingIcon: 'size-6',
tagsItem: 'text-sm',
tagsItemDeleteIcon: 'size-4',
empty: 'p-3 text-base'
}
},
variant: {
outline: 'text-highlighted bg-default ring ring-inset ring-accented',
soft: 'text-highlighted bg-elevated/50 hover:bg-elevated focus:bg-elevated disabled:bg-elevated/50',
subtle: 'text-highlighted bg-elevated ring ring-inset ring-accented',
ghost: 'text-highlighted bg-transparent hover:bg-elevated focus:bg-elevated disabled:bg-transparent dark:disabled:bg-transparent',
none: 'text-highlighted bg-transparent focus:outline-none'
},
color: {
primary: '',
secondary: '',
success: '',
info: '',
warning: '',
error: '',
neutral: ''
},
leading: {
true: ''
},
trailing: {
true: ''
},
loading: {
true: ''
},
highlight: {
true: ''
},
fixed: {
false: ''
},
type: {
file: 'file:me-1.5 file:font-medium file:text-muted file:outline-none'
},
virtualize: {
true: {
viewport: 'p-1 isolate'
},
false: {
viewport: 'divide-y divide-default'
}
},
multiple: {
true: {
root: 'flex-wrap'
},
false: {
base: 'w-full border-0 placeholder:text-dimmed disabled:cursor-not-allowed disabled:opacity-75'
}
}
},
compoundVariants: [
{
multiple: false,
fieldGroup: 'horizontal',
class: {
base: 'group-not-only:group-first:rounded-e-none group-not-only:group-last:rounded-s-none group-not-last:group-not-first:rounded-none'
}
},
{
multiple: false,
fieldGroup: 'vertical',
class: {
base: 'group-not-only:group-first:rounded-b-none group-not-only:group-last:rounded-t-none group-not-last:group-not-first:rounded-none'
}
},
{
multiple: true,
fieldGroup: 'horizontal',
class: {
base: 'not-only:first:rounded-e-none not-only:last:rounded-s-none not-last:not-first:rounded-none focus-visible:z-[1]'
}
},
{
multiple: true,
fieldGroup: 'vertical',
class: {
base: 'not-only:first:rounded-b-none not-only:last:rounded-t-none not-last:not-first:rounded-none focus-visible:z-[1]'
}
},
{
variant: 'soft',
multiple: true,
class: 'has-focus:bg-elevated has-focus-visible:outline-3'
},
{
variant: 'ghost',
multiple: true,
class: 'has-focus:bg-elevated has-focus-visible:outline-3'
},
{
color: 'primary',
multiple: true,
variant: [
'outline',
'subtle'
],
class: 'has-focus-visible:outline-3 has-focus-visible:ring-primary'
},
{
color: 'neutral',
multiple: true,
variant: [
'outline',
'subtle'
],
class: 'has-focus-visible:outline-3 has-focus-visible:ring-inverted'
},
{
color: 'primary',
variant: [
'outline',
'subtle'
],
class: 'outline-primary/25 focus-visible:outline-3 focus-visible:ring-primary'
},
{
color: 'primary',
variant: [
'soft',
'ghost'
],
class: 'outline-primary/25 focus-visible:outline-3'
},
{
color: 'primary',
highlight: true,
class: 'ring ring-inset ring-primary'
},
{
color: 'neutral',
variant: [
'outline',
'subtle'
],
class: 'outline-inverted/25 focus-visible:outline-3 focus-visible:ring-inverted'
},
{
color: 'neutral',
variant: [
'soft',
'ghost'
],
class: 'outline-inverted/25 focus-visible:outline-3'
},
{
color: 'neutral',
highlight: true,
class: 'ring ring-inset ring-inverted'
},
{
leading: true,
size: 'xs',
class: 'ps-7'
},
{
leading: true,
size: 'sm',
class: 'ps-8'
},
{
leading: true,
size: 'md',
class: 'ps-9'
},
{
leading: true,
size: 'lg',
class: 'ps-10'
},
{
leading: true,
size: 'xl',
class: 'ps-11'
},
{
trailing: true,
size: 'xs',
class: 'pe-7'
},
{
trailing: true,
size: 'sm',
class: 'pe-8'
},
{
trailing: true,
size: 'md',
class: 'pe-9'
},
{
trailing: true,
size: 'lg',
class: 'pe-10'
},
{
trailing: true,
size: 'xl',
class: 'pe-11'
},
{
loading: true,
leading: true,
class: {
leadingIcon: 'animate-spin'
}
},
{
loading: true,
leading: false,
trailing: true,
class: {
trailingIcon: 'animate-spin'
}
},
{
fixed: false,
size: 'xs',
class: 'md:text-xs'
},
{
fixed: false,
size: 'sm',
class: 'md:text-xs'
},
{
fixed: false,
size: 'md',
class: 'md:text-sm'
},
{
fixed: false,
size: 'lg',
class: 'md:text-sm'
}
],
defaultVariants: {
size: 'md',
color: 'primary',
variant: 'outline'
}
}
}
})
]
})