Skip to content

Commit 22ee5bb

Browse files
committed
fix(combobox): update combobox style, add new ComboboxEmpty component
1 parent 8032b90 commit 22ee5bb

File tree

11 files changed

+392
-79
lines changed

11 files changed

+392
-79
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
title: Combobox
3+
description: Choose from a list of suggested values with full keyboard support.
4+
status: beta
5+
source: https://github.com/typlog/ui/tree/main/src/components/combobox
6+
reka: https://reka-ui.com/docs/components/combobox
7+
---
8+
9+
<Example name="combobox/Overview.vue" variant="hide" />
10+
11+
## API Reference
12+
13+
### ComboboxRoot
14+
15+
The root element of a combobox, it contains all the parts of a combobox.
16+
17+
<PropsTable name="ComboboxRoot" />
18+
19+
### ComboboxInput
20+
21+
<PropsTable name="ComboboxInput" />
22+
23+
### ComboboxContent
24+
25+
<PropsTable name="ComboboxContent" />
26+
27+
### ComboboxGroup
28+
29+
<PropsTable name="ComboboxGroup" />
30+
31+
### ComboboxItem
32+
33+
<PropsTable name="ComboboxItem" />
34+
35+
### ComboboxLabel
36+
37+
<PropsTable name="ComboboxLabel" />
38+
39+
### ComboboxEmpty
40+
41+
<PropsTable name="ComboboxEmpty" />
42+
43+
## Examples
44+
45+
### Size
46+
47+
<Example name="combobox/Size.vue" variant="hide" />
48+
49+
### Multiple
50+
51+
<Example name="combobox/Multiple.vue" variant="hide" />
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<script setup lang="ts">
2+
import {
3+
ComboboxRoot,
4+
ComboboxContent,
5+
ComboboxGroup,
6+
ComboboxItem,
7+
ComboboxInput,
8+
ComboboxLabel,
9+
ComboboxEmpty,
10+
} from '#components'
11+
12+
const foodItems = [
13+
{
14+
name: 'Fruit',
15+
children: [
16+
{ name: 'Apple' },
17+
{ name: 'Banana' },
18+
{ name: 'Orange' },
19+
{ name: 'Honeydew' },
20+
{ name: 'Grapes' },
21+
{ name: 'Watermelon' },
22+
{ name: 'Cantaloupe' },
23+
{ name: 'Pear' },
24+
],
25+
},
26+
{
27+
name: 'Vegetable',
28+
children: [
29+
{ name: 'Cabbage' },
30+
{ name: 'Broccoli' },
31+
{ name: 'Carrots' },
32+
{ name: 'Lettuce' },
33+
{ name: 'Spinach' },
34+
{ name: 'Bok Choy' },
35+
{ name: 'Cauliflower' },
36+
{ name: 'Potatoes' },
37+
],
38+
},
39+
]
40+
</script>
41+
42+
<template>
43+
<ComboboxRoot multiple>
44+
<ComboboxInput placeholder="Select food..." />
45+
<ComboboxContent>
46+
<template
47+
v-for="group in foodItems"
48+
:key="group.name"
49+
>
50+
<ComboboxGroup v-if="group.children.length">
51+
<ComboboxLabel>
52+
{{ group.name }}
53+
</ComboboxLabel>
54+
<ComboboxItem
55+
v-for="option in group.children"
56+
:key="option.name"
57+
:value="option.name"
58+
>
59+
{{ option.name }}
60+
</ComboboxItem>
61+
</ComboboxGroup>
62+
</template>
63+
<ComboboxEmpty>
64+
<span>No food found</span>
65+
</ComboboxEmpty>
66+
</ComboboxContent>
67+
</ComboboxRoot>
68+
</template>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<script setup lang="ts">
2+
import {
3+
ComboboxRoot,
4+
ComboboxContent,
5+
ComboboxGroup,
6+
ComboboxItem,
7+
ComboboxInput,
8+
ComboboxLabel,
9+
ComboboxEmpty,
10+
} from '#components'
11+
12+
const foodItems = [
13+
{
14+
name: 'Fruit',
15+
children: [
16+
{ name: 'Apple' },
17+
{ name: 'Banana' },
18+
{ name: 'Orange' },
19+
{ name: 'Honeydew' },
20+
{ name: 'Grapes' },
21+
{ name: 'Watermelon' },
22+
{ name: 'Cantaloupe' },
23+
{ name: 'Pear' },
24+
],
25+
},
26+
{
27+
name: 'Vegetable',
28+
children: [
29+
{ name: 'Cabbage' },
30+
{ name: 'Broccoli' },
31+
{ name: 'Carrots' },
32+
{ name: 'Lettuce' },
33+
{ name: 'Spinach' },
34+
{ name: 'Bok Choy' },
35+
{ name: 'Cauliflower' },
36+
{ name: 'Potatoes' },
37+
],
38+
},
39+
]
40+
</script>
41+
42+
<template>
43+
<ComboboxRoot>
44+
<ComboboxInput placeholder="Select food..." />
45+
<ComboboxContent>
46+
<template
47+
v-for="group in foodItems"
48+
:key="group.name"
49+
>
50+
<ComboboxGroup v-if="group.children.length">
51+
<ComboboxLabel>
52+
{{ group.name }}
53+
</ComboboxLabel>
54+
<ComboboxItem
55+
v-for="option in group.children"
56+
:key="option.name"
57+
:value="option.name"
58+
>
59+
{{ option.name }}
60+
</ComboboxItem>
61+
</ComboboxGroup>
62+
</template>
63+
<ComboboxEmpty>
64+
<span>No food found</span>
65+
</ComboboxEmpty>
66+
</ComboboxContent>
67+
</ComboboxRoot>
68+
</template>

docs/examples/combobox/Size.vue

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<script setup lang="ts">
2+
import {
3+
ComboboxRoot,
4+
ComboboxContent,
5+
ComboboxItem,
6+
ComboboxInput,
7+
ComboboxEmpty,
8+
} from '#components'
9+
10+
const fruits = [
11+
{ name: 'Apple' },
12+
{ name: 'Banana' },
13+
{ name: 'Orange' },
14+
{ name: 'Honeydew' },
15+
{ name: 'Grapes' },
16+
{ name: 'Watermelon' },
17+
{ name: 'Cantaloupe' },
18+
{ name: 'Pear' },
19+
]
20+
</script>
21+
22+
<template>
23+
<div class="flex flex-items gap-4">
24+
<ComboboxRoot size="1">
25+
<ComboboxInput placeholder="Select fruit..." />
26+
<ComboboxContent>
27+
<ComboboxItem
28+
v-for="option in fruits"
29+
:key="option.name"
30+
:value="option.name"
31+
>
32+
{{ option.name }}
33+
</ComboboxItem>
34+
<ComboboxEmpty>
35+
<span>No fruit found</span>
36+
</ComboboxEmpty>
37+
</ComboboxContent>
38+
</ComboboxRoot>
39+
40+
<ComboboxRoot size="2">
41+
<ComboboxInput placeholder="Select fruit..." />
42+
<ComboboxContent>
43+
<ComboboxItem
44+
v-for="option in fruits"
45+
:key="option.name"
46+
:value="option.name"
47+
>
48+
{{ option.name }}
49+
</ComboboxItem>
50+
<ComboboxEmpty>
51+
<span>No fruit found</span>
52+
</ComboboxEmpty>
53+
</ComboboxContent>
54+
</ComboboxRoot>
55+
56+
<ComboboxRoot size="3">
57+
<ComboboxInput placeholder="Select fruit..." />
58+
<ComboboxContent>
59+
<ComboboxItem
60+
v-for="option in fruits"
61+
:key="option.name"
62+
:value="option.name"
63+
>
64+
{{ option.name }}
65+
</ComboboxItem>
66+
<ComboboxEmpty>
67+
<span>No fruit found</span>
68+
</ComboboxEmpty>
69+
</ComboboxContent>
70+
</ComboboxRoot>
71+
</div>
72+
</template>

src/components/combobox/ComboboxContent.vue

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
<script lang="ts">
2-
import type { ComboboxContentProps as _ComboboxContentProps, ComboboxContentEmits } from 'reka-ui'
2+
import type {
3+
ComboboxContentProps as RekaComboboxContentProps,
4+
ComboboxContentEmits,
5+
} from 'reka-ui'
36
import ThemeWrapper from '../provider/ThemeWrapper.vue'
47
5-
export interface ComboboxContentProps extends _ComboboxContentProps {
6-
to?: string | HTMLElement
8+
export interface ComboboxContentProps extends RekaComboboxContentProps {
79
variant?: 'solid' | 'soft'
810
}
911
</script>
@@ -31,6 +33,7 @@ const { forwardRef } = useForwardExpose()
3133
const props = withDefaults(defineProps<ComboboxContentProps>(), {
3234
variant: 'solid',
3335
position: 'popper',
36+
sideOffset: 5,
3437
})
3538
const emits = defineEmits<ComboboxContentEmits>()
3639
const forwarded = useForwardPropsEmits(props, emits)
@@ -46,7 +49,7 @@ const contentClass = computed(() => {
4649
</script>
4750

4851
<template>
49-
<ComboboxPortal :to="props.to">
52+
<ComboboxPortal>
5053
<ThemeWrapper :accent-color="context.color.value">
5154
<ComboboxContent
5255
:ref="forwardRef"
@@ -111,23 +114,73 @@ const contentClass = computed(() => {
111114
padding: var(--combobox-content-padding);
112115
}
113116
114-
.ui-ComboboxContent:has(.ui-ScrollAreaScrollbar[data-orientation='vertical']) .ui-ComboboxViewport {
117+
.ui-ComboboxContent:where(:has(.ui-ScrollAreaScrollbar[data-orientation='vertical'])) :where(.ui-ComboboxViewport) {
115118
padding-right: var(--space-3);
116119
}
117120
118121
.ui-ComboboxContent:where(.r-size-1) {
119122
--combobox-content-padding: var(--space-1);
123+
120124
--combobox-item-height: var(--space-5);
121-
--combobox-item-indicator-width: calc(var(--space-5) / 1.2);
125+
--combobox-item-font-size: var(--font-size-1);
126+
--combobox-item-line-height: var(--line-height-1);
127+
--combobox-item-letter-spacing: var(--letter-spacing-1);
128+
--combobox-item-radius: var(--radius-1);
129+
130+
--combobox-indicator-width: calc(var(--space-5) / 1.2);
131+
--combobox-indicator-icon-width: calc(8px * var(--scaling));
132+
--combobox-indicator-icon-height: calc(8px * var(--scaling));
133+
122134
--combobox-separator-margin-right: var(--space-2);
135+
136+
--combobox-label-font-size: var(--font-size-1);
137+
--combobox-label-letter-spacing: var(--letter-spacing-1);
138+
--combobox-label-line-height: var(--line-height-1);
139+
123140
border-radius: var(--radius-3);
124141
}
142+
143+
.ui-ComboboxContent:where(.r-size-2) {
144+
--combobox-item-font-size: var(--font-size-2);
145+
--combobox-item-letter-spacing: var(--letter-spacing-2);
146+
}
147+
148+
.ui-ComboboxContent:where(.r-size-3) {
149+
--combobox-item-font-size: var(--font-size-3);
150+
--combobox-item-letter-spacing: var(--letter-spacing-3);
151+
}
152+
125153
.ui-ComboboxContent:where(.r-size-2),
126154
.ui-ComboboxContent:where(.r-size-3) {
127155
--combobox-content-padding: var(--space-2);
156+
--combobox-item-radius: var(--radius-2);
128157
--combobox-item-height: var(--space-6);
129-
--combobox-item-indicator-width: var(--space-5);
158+
--combobox-item-line-height: var(--line-height-2);
159+
--combobox-indicator-width: var(--space-5);
160+
--combobox-indicator-icon-width: calc(10px * var(--scaling));
161+
--combobox-indicator-icon-height: calc(10px * var(--scaling));
130162
--combobox-separator-margin-right: var(--space-3);
163+
164+
--combobox-label-font-size: var(--font-size-2);
165+
--combobox-label-letter-spacing: var(--letter-spacing-2);
166+
--combobox-label-line-height: var(--line-height-2);
167+
131168
border-radius: var(--radius-4);
132169
}
170+
171+
.ui-ComboboxContent:where(.r-variant-solid) {
172+
--combobox-highlighted-background-color: var(--accent-9);
173+
--combobox-highlighted-text-color: var(--accent-contrast);
174+
}
175+
.ui-ComboboxContent:where(.r-variant-solid.r-high-contrast) {
176+
--combobox-highlighted-background-color: var(--accent-12);
177+
--combobox-highlighted-text-color: var(--accent-1);
178+
}
179+
.ui-ComboboxContent:where(.r-variant-soft) {
180+
--combobox-highlighted-background-color: var(--accent-a3);
181+
--combobox-highlighted-text-color: var(--accent-a11);
182+
}
183+
.ui-ComboboxContent:where(.r-variant-soft.r-high-contrast) {
184+
--combobox-highlighted-text-color: var(--accent-12);
185+
}
133186
</style>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<script setup lang="ts">
2+
import { ComboboxEmpty } from 'reka-ui'
3+
</script>
4+
5+
<template>
6+
<ComboboxEmpty class="ui-ComboboxEmpty">
7+
<slot></slot>
8+
</ComboboxEmpty>
9+
</template>
10+
11+
<style>
12+
.ui-ComboboxEmpty {
13+
box-sizing: border-box;
14+
outline: none;
15+
scroll-margin: var(--combobox-content-padding) 0;
16+
user-select: none;
17+
cursor: default;
18+
padding-left: calc(var(--combobox-indicator-width) / 2);
19+
padding-right: var(--combobox-indicator-width);
20+
font-size: var(--combobox-item-font-size);
21+
line-height: var(--combobox-item-line-height);
22+
letter-spacing: var(--combobox-item-letter-spacing);
23+
color: var(--gray-11);
24+
}
25+
</style>

0 commit comments

Comments
 (0)