Skip to content

Commit 65a8608

Browse files
Merge pull request #602 from thejackshelton/improve-combobox
New bind:selectedIndex syntax, bug fixes
2 parents adfd7cf + a320959 commit 65a8608

File tree

14 files changed

+89
-137
lines changed

14 files changed

+89
-137
lines changed

.changeset/honest-timers-dream.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@qwik-ui/headless': patch
3+
---
4+
5+
bind syntax Sig suffix removed, new bind:selectedIndex prop, bug fixes

apps/website/src/routes/docs/headless/combobox/examples/hero.tsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ import {
1111
ComboboxPopover,
1212
} from '@qwik-ui/headless';
1313

14-
import { component$ } from '@builder.io/qwik';
14+
import { component$, useSignal } from '@builder.io/qwik';
1515

1616
export default component$(() => {
17+
const selectedOptionIndexSig = useSignal<number>(-1);
18+
1719
const objectExample = [
1820
{ testValue: 'alice', testLabel: 'Alice', disabled: true },
1921
{ testValue: 'joana', testLabel: 'Joana', disabled: true },
@@ -40,32 +42,32 @@ export default component$(() => {
4042
optionLabelKey="testLabel"
4143
optionDisabledKey="disabled"
4244
class="relative"
45+
bind:selectedIndex={selectedOptionIndexSig}
4346
>
4447
<ComboboxLabel class="font-semibold">Personal Trainers ⚡</ComboboxLabel>
4548
<ComboboxControl class="relative flex items-center rounded-sm border">
4649
<ComboboxInput
4750
placeholder="Jim"
48-
class="px-d2 bg-background placeholder:text-muted-foreground w-44 rounded-sm px-2 pr-6"
51+
class="px-d2 rounded-sm bg-slate-900 px-2 pr-6 text-white placeholder:text-slate-400"
4952
/>
5053
<ComboboxTrigger class="group absolute right-0 h-6 w-6">
51-
<ComboboxIcon class="stroke-foreground transition-transform duration-[450ms] group-aria-expanded:-rotate-180" />
54+
<ComboboxIcon class="stroke-white transition-transform duration-[450ms] group-aria-expanded:-rotate-180" />
5255
</ComboboxTrigger>
5356
</ComboboxControl>
54-
<ComboboxPopover gutter={8}>
57+
<ComboboxPopover class="rounded-sm" gutter={8}>
5558
<ComboboxListbox
56-
class="w-44 rounded-sm border-[1px] border-slate-400 bg-slate-900 px-4 py-2"
59+
class="rounded-sm border-[1px] border-slate-400 bg-slate-900 px-4 py-2"
5760
optionRenderer$={(option: ResolvedOption, index: number) => {
5861
const myData = option.option as MyData;
5962
return (
6063
<ComboboxOption
6164
key={option.key}
6265
resolved={option}
6366
index={index}
64-
class="hover:bg-accent aria-disabled:text-muted-foreground aria-disabled:hover:bg-muted aria-selected:border-border aria-selected:bg-accent group flex justify-between rounded-sm border border-transparent px-2 aria-disabled:font-light aria-selected:cursor-pointer"
67+
class="aria-disabled:text-muted-foreground data-[highlighted]:border-border group flex justify-between gap-4 rounded-sm border border-transparent px-2 text-white aria-disabled:font-light aria-disabled:hover:border-slate-500 data-[highlighted]:cursor-pointer data-[highlighted]:bg-slate-800"
6568
>
66-
<span class="duration-350 block transition-transform group-aria-selected:translate-x-[3px]">
67-
{myData.testLabel}
68-
</span>
69+
<span>{myData.testLabel}</span>
70+
{selectedOptionIndexSig.value === index && <span>Selected</span>}
6971
</ComboboxOption>
7072
);
7173
}}

apps/website/src/routes/docs/headless/combobox/examples/highlighted-index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export default component$(() => {
2828
<Combobox
2929
class="w-fit"
3030
options={highlightedExample}
31-
bind:highlightedIndexSig={highlightedIndexSig}
31+
bind:highlightedIndex={highlightedIndexSig}
3232
>
3333
<ComboboxControl class="relative flex items-center rounded-sm border">
3434
<ComboboxInput class="px-d2 bg-background placeholder:text-muted-foreground w-fit rounded-sm px-2 pr-6" />

apps/website/src/routes/docs/headless/combobox/examples/placement.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export default component$(() => {
3333
class="w-fit"
3434
options={placementExample}
3535
optionDisabledKey="myDisabledKey"
36-
bind:inputValueSig={inputValueSig}
36+
bind:inputValue={inputValueSig}
3737
>
3838
<ComboboxLabel>Positions</ComboboxLabel>
3939
<ComboboxControl class="relative mt-2 flex items-center rounded-sm border">

apps/website/src/routes/docs/headless/combobox/examples/search-bar.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ export default component$(() => {
3838

3939
return (
4040
<Combobox
41-
bind:inputValueSig={inputValueSig}
42-
bind:highlightedIndexSig={highlightedIndexSig}
43-
bind:isListboxOpenSig={isListboxOpenSig}
41+
bind:inputValue={inputValueSig}
42+
bind:highlightedIndex={highlightedIndexSig}
43+
bind:isListboxOpen={isListboxOpenSig}
4444
optionValueKey="component"
4545
class="w-fit"
4646
options={components}

apps/website/src/routes/docs/headless/combobox/examples/shift.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export default component$(() => {
2626
<Combobox
2727
class="w-fit"
2828
options={shiftExample}
29-
bind:isListboxOpenSig={isListboxOpenSig}
29+
bind:isListboxOpen={isListboxOpenSig}
3030
>
3131
<ComboboxLabel class=" font-semibold">Fruits 🍓</ComboboxLabel>
3232
<ComboboxControl class="relative flex items-center rounded-sm border">

apps/website/src/routes/docs/headless/combobox/examples/signal-binds.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ export default component$(() => {
3030
<Combobox
3131
class="w-fit"
3232
options={signalsExample}
33-
bind:isListboxOpenSig={isListboxOpenSig}
34-
bind:highlightedIndexSig={highlightedIndexSig}
33+
bind:isListboxOpen={isListboxOpenSig}
34+
bind:highlightedIndex={highlightedIndexSig}
3535
>
3636
<ComboboxControl class="relative flex items-center rounded-sm border">
3737
<ComboboxInput

apps/website/src/routes/docs/headless/combobox/index.mdx

Lines changed: 25 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -41,27 +41,6 @@ Qwik UI's Combobox implementation follows the [WAI-Aria Combobox specifications]
4141

4242
<br />
4343

44-
> In Beta, we're currently supporting the **`Autocomplete`** configuration. We aim to support other combobox configurations according to our [roadmap](https://github.com/qwikifiers/qwik-ui/issues/405)
45-
46-
<br />
47-
48-
The Combobox component makes use of [portals](https://qwik.builder.io/docs/cookbook/portal/#portal). A basic use case for a portal is to prevent overflow issues in your UI. To support portals in Qwik UI, please add the following around your layout.tsx.
49-
50-
<CodeSnippet name="qwik-ui-provider" />
51-
52-
## **Context Caveats**
53-
54-
Portals are still currently in **Beta**, as a result, you may experience an issue using your own context to pass data into the portal children.
55-
56-
If you do experience any context related issues, add the following **contextIds** prop to the **ComboboxPortal** component.
57-
58-
<CodeSnippet name="context-ids" />
59-
60-
It takes in an array of string context id's as a prop. We also have a live example below with context.
61-
If you are not using context inside the portal children, this will not be an issue.
62-
63-
<br />
64-
6544
## Building blocks
6645

6746
<CodeSnippet name="building-blocks" />
@@ -91,8 +70,8 @@ If you are not using context inside the portal children, this will not be an iss
9170
description: `A button that toggles the corresponding listbox when clicked.`,
9271
},
9372
{
94-
name: 'ComboboxPortal',
95-
description: `A portal component that teleports the children outside its parent when the listbox state is open.`,
73+
name: 'ComboboxPopover',
74+
description: `A Popover component that teleports the children outside its parent when the listbox state is open.`,
9675
},
9776
{
9877
name: 'ComboboxListbox',
@@ -191,29 +170,34 @@ To disable this behavior, set `disableOnBlur={true}` on the Input.
191170

192171
The Combobox component allows you to customize its state signals. This can be useful if you want to control or observe these states externally.
193172

194-
This involves creating a signal and passing it in using the [bind syntax](https://qwik.builder.io/docs/components/rendering/#bind-attribute), such as in the Qwik docs.
173+
In reality it is a signal prop, we prefer using this syntax, because we believe it is familiar to Qwik developers with the [bind syntax](https://qwik.builder.io/docs/components/rendering/#bind-attribute).
195174

196175
<APITable
197176
propDescriptors={[
198177
{
199-
name: 'bind:isListboxOpenSig',
178+
name: 'bind:inputValue',
200179
type: 'Signal',
201-
description: 'Controls the open state of the listbox.',
180+
description: 'Controls the current value of the input.',
202181
},
203182
{
204-
name: 'bind:isInputFocusedSig',
183+
name: 'bind:selectedIndex',
205184
type: 'Signal',
206-
description: 'Controls the focus state of the input.',
185+
description: 'Controls the selected option index.',
207186
},
208187
{
209-
name: 'bind:highlightedIndexSig',
188+
name: 'bind:isListboxOpen',
210189
type: 'Signal',
211-
description: 'Controls which option is highlighted.',
190+
description: 'Controls the open state of the listbox.',
212191
},
213192
{
214-
name: 'bind:inputValueSig',
193+
name: 'bind:isInputFocused',
215194
type: 'Signal',
216-
description: 'Controls the current value of the input.',
195+
description: 'Controls the focus state of the input.',
196+
},
197+
{
198+
name: 'bind:highlightedIndex',
199+
type: 'Signal',
200+
description: 'Controls which option is highlighted.',
217201
},
218202
]}
219203
/>
@@ -319,22 +303,27 @@ The Combobox component API provides a set of properties that allow you to custom
319303
description: 'The default label for the combobox.',
320304
},
321305
{
322-
name: 'bind:isListboxOpenSig',
306+
name: 'bind:selectedIndex',
307+
type: `Signal<number>`,
308+
description: 'A signal for the selected option index.',
309+
},
310+
{
311+
name: 'bind:isListboxOpen',
323312
type: `Signal<boolean>`,
324313
description: 'A signal for the open state of the listbox.',
325314
},
326315
{
327-
name: 'bind:isInputFocusedSig',
316+
name: 'bind:isInputFocused',
328317
type: 'Signal<boolean>',
329318
description: 'A signal for the focus state of the input.',
330319
},
331320
{
332-
name: 'bind:inputValueSig',
321+
name: 'bind:inputValue',
333322
type: 'Signal<string>',
334323
description: 'A signal for the current value of the input.',
335324
},
336325
{
337-
name: 'bind:highlightedIndexSig',
326+
name: 'bind:highlightedIndex',
338327
type: 'Signal<number>',
339328
description: 'A signal for the highlighted option index.',
340329
},

packages/kit-headless/src/components/combobox/combobox-context.type.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export interface ComboboxContext<O extends Option = Option> {
2121
isInputFocusedSig: Signal<boolean | undefined>;
2222
isListboxOpenSig: Signal<boolean | undefined>;
2323
highlightedIndexSig: Signal<number>;
24-
selectedOptionIndexSig: Signal<number>;
24+
selectedIndexSig: Signal<number>;
2525

2626
// option settings
2727
optionValueKey: string;

packages/kit-headless/src/components/combobox/combobox-input.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {
44
useContext,
55
useSignal,
66
useTask$,
7-
type QwikKeyboardEvent,
87
type ContextId,
98
PropsOf,
109
} from '@builder.io/qwik';
@@ -43,7 +42,7 @@ export const ComboboxInput = component$(
4342
context.inputValueSig.value = inputElement.value;
4443
});
4544

46-
const onKeydownBehavior$ = $((e: QwikKeyboardEvent) => {
45+
const onKeydownBehavior$ = $((e: KeyboardEvent) => {
4746
if (e.key === 'ArrowDown') {
4847
if (context.isListboxOpenSig.value) {
4948
const nextEnabledOptionIndex = getNextEnabledOptionIndex(
@@ -73,6 +72,7 @@ export const ComboboxInput = component$(
7372

7473
if (e.key === 'Enter') {
7574
context.isListboxOpenSig.value = false;
75+
context.selectedIndexSig.value = context.highlightedIndexSig.value;
7676

7777
// if they somehow manage to highlight a disabled option (bug)
7878
if (

0 commit comments

Comments
 (0)