Skip to content

Commit 1a46394

Browse files
feat(components): add new content-top and content-bottom slots (#3886)
Co-authored-by: Benjamin Canac <[email protected]>
1 parent 9ca213b commit 1a46394

File tree

9 files changed

+36
-8
lines changed

9 files changed

+36
-8
lines changed

playground/app/pages/components/tabs.vue

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,6 @@ const items = [{
5959
<template #custom="{ item }">
6060
<span class="text-muted">Custom: {{ item.content }}</span>
6161
</template>
62-
63-
<template #list-trailing>
64-
<UButton
65-
icon="lucide:refresh-cw"
66-
variant="soft"
67-
class="ml-2"
68-
/>
69-
</template>
7062
</UTabs>
7163
</div>
7264
</div>

src/runtime/components/ContextMenu.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ export type ContextMenuSlots<
9090
'item-leading': SlotProps<T>
9191
'item-label': SlotProps<T>
9292
'item-trailing': SlotProps<T>
93+
'content-top': (props?: {}) => any
94+
'content-bottom': (props?: {}) => any
9395
} & DynamicSlots<MergeTypes<T>, 'leading' | 'label' | 'trailing', { active?: boolean, index: number }>
9496
9597
</script>

src/runtime/components/ContextMenuContent.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ const groups = computed<ContextMenuItem[][]>(() =>
107107

108108
<ContextMenu.Portal v-bind="portalProps">
109109
<component :is="sub ? ContextMenu.SubContent : ContextMenu.Content" :class="props.class" v-bind="contentProps">
110+
<slot name="content-top" />
111+
110112
<ContextMenu.Group v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group({ class: uiOverride?.group })">
111113
<template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
112114
<ContextMenu.Label v-if="item.type === 'label'" :class="ui.label({ class: uiOverride?.label })">
@@ -171,6 +173,8 @@ const groups = computed<ContextMenuItem[][]>(() =>
171173
</ContextMenu.Group>
172174

173175
<slot />
176+
177+
<slot name="content-bottom" />
174178
</component>
175179
</ContextMenu.Portal>
176180
</template>

src/runtime/components/DropdownMenu.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ export type DropdownMenuSlots<
9898
'item-leading': SlotProps<T>
9999
'item-label': SlotProps<T>
100100
'item-trailing': SlotProps<T>
101+
'content-top': (props?: {}) => any
102+
'content-bottom': (props?: {}) => any
101103
} & DynamicSlots<MergeTypes<T>, 'leading' | 'label' | 'trailing', { active?: boolean, index: number }>
102104
103105
</script>

src/runtime/components/DropdownMenuContent.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ const groups = computed<DropdownMenuItem[][]>(() =>
113113

114114
<DropdownMenu.Portal v-bind="portalProps">
115115
<component :is="sub ? DropdownMenu.SubContent : DropdownMenu.Content" :class="props.class" v-bind="contentProps">
116+
<slot name="content-top" />
117+
116118
<DropdownMenu.Group v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group({ class: uiOverride?.group })">
117119
<template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
118120
<DropdownMenu.Label v-if="item.type === 'label'" :class="ui.label({ class: uiOverride?.label })">
@@ -179,6 +181,8 @@ const groups = computed<DropdownMenuItem[][]>(() =>
179181
</DropdownMenu.Group>
180182

181183
<slot />
184+
185+
<slot name="content-bottom" />
182186
</component>
183187
</DropdownMenu.Portal>
184188
</template>

src/runtime/components/InputMenu.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ export interface InputMenuSlots<
162162
'item-trailing': SlotProps<T>
163163
'tags-item-text': SlotProps<T>
164164
'tags-item-delete': SlotProps<T>
165+
'content-top': (props?: {}) => any
166+
'content-bottom': (props?: {}) => any
165167
'create-item-label'(props: { item: string }): any
166168
}
167169
</script>
@@ -478,6 +480,8 @@ defineExpose({
478480

479481
<ComboboxPortal v-bind="portalProps">
480482
<ComboboxContent :class="ui.content({ class: props.ui?.content })" v-bind="contentProps">
483+
<slot name="content-top" />
484+
481485
<ComboboxEmpty :class="ui.empty({ class: props.ui?.empty })">
482486
<slot name="empty" :search-term="searchTerm">
483487
{{ searchTerm ? t('inputMenu.noMatch', { searchTerm }) : t('inputMenu.noData') }}
@@ -537,6 +541,8 @@ defineExpose({
537541
<ReuseCreateItemTemplate v-if="createItem && createItemPosition === 'bottom'" />
538542
</ComboboxViewport>
539543

544+
<slot name="content-bottom" />
545+
540546
<ComboboxArrow v-if="!!arrow" v-bind="arrowProps" :class="ui.arrow({ class: props.ui?.arrow })" />
541547
</ComboboxContent>
542548
</ComboboxPortal>

src/runtime/components/NavigationMenu.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ export type NavigationMenuSlots<
123123
'item-label': SlotProps<T>
124124
'item-trailing': SlotProps<T>
125125
'item-content': SlotProps<T>
126+
'list-leading': (props?: {}) => any
127+
'list-trailing': (props?: {}) => any
126128
} & DynamicSlots<MergeTypes<T>, 'leading' | 'label' | 'trailing' | 'content', { index: number, active?: boolean }>
127129
128130
</script>
@@ -303,6 +305,8 @@ const lists = computed<NavigationMenuItem[][]>(() =>
303305
</DefineItemTemplate>
304306

305307
<NavigationMenuRoot v-bind="rootProps" :data-collapsed="collapsed" :class="ui.root({ class: [props.class, props.ui?.root] })">
308+
<slot name="list-leading" />
309+
306310
<template v-for="(list, listIndex) in lists" :key="`list-${listIndex}`">
307311
<NavigationMenuList :class="ui.list({ class: props.ui?.list })">
308312
<ReuseItemTemplate v-for="(item, index) in list" :key="`list-${listIndex}-${index}`" :item="item" :index="index" :class="ui.item({ class: props.ui?.item })" />
@@ -311,6 +315,8 @@ const lists = computed<NavigationMenuItem[][]>(() =>
311315
<div v-if="orientation === 'vertical' && listIndex < lists.length - 1" :class="ui.separator({ class: props.ui?.separator })" />
312316
</template>
313317

318+
<slot name="list-trailing" />
319+
314320
<div v-if="orientation === 'horizontal'" :class="ui.viewportWrapper({ class: props.ui?.viewportWrapper })">
315321
<NavigationMenuIndicator v-if="arrow" :class="ui.indicator({ class: props.ui?.indicator })">
316322
<div :class="ui.arrow({ class: props.ui?.arrow })" />

src/runtime/components/Select.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ export interface SelectSlots<
126126
'item-leading': SlotProps<T>
127127
'item-label': SlotProps<T>
128128
'item-trailing': SlotProps<T>
129+
'content-top': (props?: {}) => any
130+
'content-bottom': (props?: {}) => any
129131
}
130132
</script>
131133

@@ -264,6 +266,8 @@ function isSelectItem(item: SelectItem): item is SelectItemBase {
264266

265267
<SelectPortal v-bind="portalProps">
266268
<SelectContent :class="ui.content({ class: props.ui?.content })" v-bind="contentProps">
269+
<slot name="content-top" />
270+
267271
<SelectViewport :class="ui.viewport({ class: props.ui?.viewport })">
268272
<SelectGroup v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group({ class: props.ui?.group })">
269273
<template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
@@ -313,6 +317,8 @@ function isSelectItem(item: SelectItem): item is SelectItemBase {
313317
</SelectGroup>
314318
</SelectViewport>
315319

320+
<slot name="content-bottom" />
321+
316322
<SelectArrow v-if="!!arrow" v-bind="arrowProps" :class="ui.arrow({ class: props.ui?.arrow })" />
317323
</SelectContent>
318324
</SelectPortal>

src/runtime/components/SelectMenu.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ export interface SelectMenuSlots<
156156
'item-leading': SlotProps<T>
157157
'item-label': SlotProps<T>
158158
'item-trailing': SlotProps<T>
159+
'content-top': (props?: {}) => any
160+
'content-bottom': (props?: {}) => any
159161
'create-item-label'(props: { item: string }): any
160162
}
161163
</script>
@@ -401,6 +403,8 @@ function isSelectItem(item: SelectMenuItem): item is _SelectMenuItem {
401403
<ComboboxPortal v-bind="portalProps">
402404
<ComboboxContent :class="ui.content({ class: props.ui?.content })" v-bind="contentProps">
403405
<FocusScope trapped :class="ui.focusScope({ class: props.ui?.focusScope })">
406+
<slot name="content-top" />
407+
404408
<ComboboxInput v-if="!!searchInput" v-model="searchTerm" :display-value="() => searchTerm" as-child>
405409
<UInput autofocus autocomplete="off" v-bind="searchInputProps" :class="ui.input({ class: props.ui?.input })" />
406410
</ComboboxInput>
@@ -463,6 +467,8 @@ function isSelectItem(item: SelectMenuItem): item is _SelectMenuItem {
463467

464468
<ReuseCreateItemTemplate v-if="createItem && createItemPosition === 'bottom'" />
465469
</ComboboxViewport>
470+
471+
<slot name="content-bottom" />
466472
</FocusScope>
467473

468474
<ComboboxArrow v-if="!!arrow" v-bind="arrowProps" :class="ui.arrow({ class: props.ui?.arrow })" />

0 commit comments

Comments
 (0)