Skip to content

Commit eaeffcc

Browse files
committed
fix(styled select): decouple the API to prevent index not found bug
1 parent 2ec4270 commit eaeffcc

File tree

4 files changed

+88
-34
lines changed

4 files changed

+88
-34
lines changed

apps/website/src/routes/docs/styled/select/examples/hero.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { component$ } from '@builder.io/qwik';
2+
import { LuCheck } from '@qwikest/icons/lucide';
23
import { Select } from '~/components/ui';
34

45
export default component$(() => {
@@ -10,10 +11,15 @@ export default component$(() => {
1011
<Select.Trigger>
1112
<Select.DisplayText placeholder="Select an option" />
1213
</Select.Trigger>
13-
<Select.Popover>
14+
<Select.Popover gutter={8}>
1415
<Select.Listbox>
1516
{users.map((user) => (
16-
<Select.Item key={user}>{user}</Select.Item>
17+
<Select.Item key={user}>
18+
<Select.ItemLabel>{user}</Select.ItemLabel>
19+
<Select.ItemIndicator>
20+
<LuCheck class="h-4 w-4" />
21+
</Select.ItemIndicator>
22+
</Select.Item>
1723
))}
1824
</Select.Listbox>
1925
</Select.Popover>

apps/website/src/routes/docs/styled/select/index.mdx

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { statusByComponent } from '~/_state/component-statuses';
1010

1111
Displays a list of options for the user to pick from — triggered by a button.
1212

13-
{/* <Showcase name="hero" /> */}
13+
<Showcase name="hero" />
1414

1515
## Installation
1616

@@ -24,16 +24,23 @@ qwik-ui add select
2424
import { PropsOf, Slot, component$ } from '@builder.io/qwik';
2525
import { Select as HeadlessSelect } from '@qwik-ui/headless';
2626
import { cn } from '@qwik-ui/utils';
27-
import { LuCheck, LuFilter } from '@qwikest/icons/lucide';
27+
import { LuCheck, LuChevronDown } from '@qwikest/icons/lucide';
2828

29-
const Root = HeadlessSelect.Root;
29+
const Root = (props: PropsOf<typeof HeadlessSelect.Root>) => (
30+
<HeadlessSelect.Root
31+
{...props}
32+
selectItemComponent={Item}
33+
selectItemLabelComponent={ItemLabel}
34+
selectLabelComponent={Label}
35+
/>
36+
);
3037

3138
const Label = component$<PropsOf<typeof HeadlessSelect.Label>>(({ ...props }) => {
3239
return (
3340
<>
3441
<HeadlessSelect.Label
35-
class={cn('px-2 py-1.5 text-sm font-semibold', props.class)}
3642
{...props}
43+
class={cn('px-2 py-1.5 text-sm font-semibold', props.class)}
3744
>
3845
<Slot />
3946
</HeadlessSelect.Label>
@@ -45,14 +52,14 @@ const Trigger = component$<PropsOf<typeof HeadlessSelect.Trigger>>(({ ...props }
4552
return (
4653
<>
4754
<HeadlessSelect.Trigger
55+
{...props}
4856
class={cn(
4957
'flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
5058
props.class,
51-
{ ...props },
5259
)}
5360
>
5461
<Slot />
55-
<LuFilter class="h-4 w-4 opacity-50" />
62+
<LuChevronDown class="h-4 w-4 opacity-50" />
5663
</HeadlessSelect.Trigger>
5764
</>
5865
);
@@ -64,12 +71,12 @@ const Popover = component$<PropsOf<typeof HeadlessSelect.Popover>>(({ ...props }
6471
return (
6572
<>
6673
<HeadlessSelect.Popover
74+
{...props}
6775
class={cn(
68-
'w-full max-w-[15rem]',
76+
'w-full max-w-[15rem] data-[open]:animate-in data-[closing]:animate-out data-[closing]:fade-out-0 data-[open]:fade-in-0 data-[closing]:zoom-out-95 data-[open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
6977
// 'overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md',
7078
props.class,
7179
)}
72-
{...props}
7380
>
7481
<Slot />
7582
</HeadlessSelect.Popover>
@@ -82,11 +89,11 @@ const Listbox = component$<ListboxProps>(({ ...props }) => {
8289
return (
8390
<>
8491
<HeadlessSelect.Listbox
92+
{...props}
8593
class={cn(
86-
'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
94+
'relative z-50 max-h-96 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md',
8795
props.class,
8896
)}
89-
{...props}
9097
>
9198
<Slot />
9299
</HeadlessSelect.Listbox>
@@ -101,20 +108,35 @@ const GroupLabel = HeadlessSelect.GroupLabel;
101108
const Item = component$<PropsOf<typeof HeadlessSelect.Item>>(({ ...props }) => {
102109
return (
103110
<HeadlessSelect.Item
111+
{...props}
104112
class={cn(
105113
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
114+
'data-[highlighted]:border-base data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground',
106115
props.class,
107116
)}
108117
>
118+
<Slot />
119+
</HeadlessSelect.Item>
120+
);
121+
});
122+
123+
const ItemIndicator = component$<PropsOf<typeof HeadlessSelect.ItemIndicator>>(
124+
({ ...props }) => {
125+
return (
109126
<span class="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
110-
<HeadlessSelect.ItemIndicator>
127+
<HeadlessSelect.ItemIndicator {...props}>
111128
<LuCheck class="h-4 w-4" />
112129
</HeadlessSelect.ItemIndicator>
113130
</span>
114-
<HeadlessSelect.ItemLabel>
115-
<Slot />
116-
</HeadlessSelect.ItemLabel>
117-
</HeadlessSelect.Item>
131+
);
132+
},
133+
);
134+
135+
const ItemLabel = component$<PropsOf<typeof HeadlessSelect.ItemLabel>>(({ ...props }) => {
136+
return (
137+
<HeadlessSelect.ItemLabel {...props}>
138+
<Slot />
139+
</HeadlessSelect.ItemLabel>
118140
);
119141
});
120142

@@ -128,5 +150,7 @@ export const Select = {
128150
Group,
129151
GroupLabel,
130152
Item,
153+
ItemIndicator,
154+
ItemLabel,
131155
};
132156
```
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { Slot, component$, useContext } from '@builder.io/qwik';
1+
import { PropsOf, Slot, component$, useContext } from '@builder.io/qwik';
22
import { selectItemContextId } from './select-context';
33

4-
export const HSelectItemIndicator = component$(() => {
4+
export const HSelectItemIndicator = component$<PropsOf<'span'>>(() => {
55
const selectContext = useContext(selectItemContextId);
66

7-
return <>{selectContext.isSelectedSig.value && <Slot />}</>;
7+
return <span>{selectContext.isSelectedSig.value && <Slot />}</span>;
88
});

packages/kit-styled/src/components/select/select.tsx

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
import { PropsOf, Slot, component$ } from '@builder.io/qwik';
22
import { Select as HeadlessSelect } from '@qwik-ui/headless';
33
import { cn } from '@qwik-ui/utils';
4-
import { LuCheck, LuFilter } from '@qwikest/icons/lucide';
4+
import { LuCheck, LuChevronDown } from '@qwikest/icons/lucide';
55

6-
const Root = HeadlessSelect.Root;
6+
const Root = (props: PropsOf<typeof HeadlessSelect.Root>) => (
7+
<HeadlessSelect.Root
8+
{...props}
9+
selectItemComponent={Item}
10+
selectItemLabelComponent={ItemLabel}
11+
selectLabelComponent={Label}
12+
/>
13+
);
714

815
const Label = component$<PropsOf<typeof HeadlessSelect.Label>>(({ ...props }) => {
916
return (
1017
<>
1118
<HeadlessSelect.Label
12-
class={cn('px-2 py-1.5 text-sm font-semibold', props.class)}
1319
{...props}
20+
class={cn('px-2 py-1.5 text-sm font-semibold', props.class)}
1421
>
1522
<Slot />
1623
</HeadlessSelect.Label>
@@ -22,14 +29,14 @@ const Trigger = component$<PropsOf<typeof HeadlessSelect.Trigger>>(({ ...props }
2229
return (
2330
<>
2431
<HeadlessSelect.Trigger
32+
{...props}
2533
class={cn(
2634
'flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
2735
props.class,
28-
{ ...props },
2936
)}
3037
>
3138
<Slot />
32-
<LuFilter class="h-4 w-4 opacity-50" />
39+
<LuChevronDown class="h-4 w-4 opacity-50" />
3340
</HeadlessSelect.Trigger>
3441
</>
3542
);
@@ -41,12 +48,12 @@ const Popover = component$<PropsOf<typeof HeadlessSelect.Popover>>(({ ...props }
4148
return (
4249
<>
4350
<HeadlessSelect.Popover
51+
{...props}
4452
class={cn(
45-
'w-full max-w-[15rem]',
53+
'w-full max-w-[15rem] data-[open]:animate-in data-[closing]:animate-out data-[closing]:fade-out-0 data-[open]:fade-in-0 data-[closing]:zoom-out-95 data-[open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
4654
// 'overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md',
4755
props.class,
4856
)}
49-
{...props}
5057
>
5158
<Slot />
5259
</HeadlessSelect.Popover>
@@ -59,11 +66,11 @@ const Listbox = component$<ListboxProps>(({ ...props }) => {
5966
return (
6067
<>
6168
<HeadlessSelect.Listbox
69+
{...props}
6270
class={cn(
63-
'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
71+
'relative z-50 max-h-96 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md',
6472
props.class,
6573
)}
66-
{...props}
6774
>
6875
<Slot />
6976
</HeadlessSelect.Listbox>
@@ -78,20 +85,35 @@ const GroupLabel = HeadlessSelect.GroupLabel;
7885
const Item = component$<PropsOf<typeof HeadlessSelect.Item>>(({ ...props }) => {
7986
return (
8087
<HeadlessSelect.Item
88+
{...props}
8189
class={cn(
8290
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
91+
'data-[highlighted]:border-base data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground',
8392
props.class,
8493
)}
8594
>
95+
<Slot />
96+
</HeadlessSelect.Item>
97+
);
98+
});
99+
100+
const ItemIndicator = component$<PropsOf<typeof HeadlessSelect.ItemIndicator>>(
101+
({ ...props }) => {
102+
return (
86103
<span class="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
87-
<HeadlessSelect.ItemIndicator>
104+
<HeadlessSelect.ItemIndicator {...props}>
88105
<LuCheck class="h-4 w-4" />
89106
</HeadlessSelect.ItemIndicator>
90107
</span>
91-
<HeadlessSelect.ItemLabel>
92-
<Slot />
93-
</HeadlessSelect.ItemLabel>
94-
</HeadlessSelect.Item>
108+
);
109+
},
110+
);
111+
112+
const ItemLabel = component$<PropsOf<typeof HeadlessSelect.ItemLabel>>(({ ...props }) => {
113+
return (
114+
<HeadlessSelect.ItemLabel {...props}>
115+
<Slot />
116+
</HeadlessSelect.ItemLabel>
95117
);
96118
});
97119

@@ -105,4 +127,6 @@ export const Select = {
105127
Group,
106128
GroupLabel,
107129
Item,
130+
ItemIndicator,
131+
ItemLabel,
108132
};

0 commit comments

Comments
 (0)