Skip to content

Commit fb09903

Browse files
committed
Merge branch 'main' into pkg.pr.new
2 parents 9f8fb26 + 33ad8b2 commit fb09903

File tree

11 files changed

+1617
-999
lines changed

11 files changed

+1617
-999
lines changed

.changeset/orange-points-reflect.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@qwik-ui/styled': patch
3+
---
4+
5+
FEAT new styled select component

apps/website/src/_state/component-statuses.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const statusByComponent: ComponentKitsStatuses = {
2727
Popover: ComponentStatus.Draft,
2828
Progress: ComponentStatus.Draft,
2929
RadioGroup: ComponentStatus.Draft,
30+
Select: ComponentStatus.Draft,
3031
Separator: ComponentStatus.Beta,
3132
Skeleton: ComponentStatus.Beta,
3233
Tabs: ComponentStatus.Beta,

apps/website/src/routes/docs/styled/menu.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
- [Popover](/docs/styled/popover)
3030
- [Progress](/docs/styled/progress)
3131
- [RadioGroup](/docs/styled/radio-group)
32+
- [Select](/docs/styled/select)
3233
- [Separator](/docs/styled/separator)
3334
- [Skeleton](/docs/styled/skeleton)
3435
- [Tabs](/docs/styled/tabs)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { component$ } from '@builder.io/qwik';
2+
import { LuCheck } from '@qwikest/icons/lucide';
3+
import { Select } from '~/components/ui';
4+
5+
export default component$(() => {
6+
const users = ['Tim', 'Ryan', 'Jim', 'Jessie', 'Abby'];
7+
8+
return (
9+
<Select.Root>
10+
<Select.Label>Logged in users</Select.Label>
11+
<Select.Trigger>
12+
<Select.DisplayText placeholder="Select an option" />
13+
</Select.Trigger>
14+
<Select.Popover gutter={8}>
15+
<Select.Listbox>
16+
{users.map((user) => (
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>
23+
))}
24+
</Select.Listbox>
25+
</Select.Popover>
26+
</Select.Root>
27+
);
28+
});

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

Lines changed: 147 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,153 @@ title: Qwik UI | Styled Select Component
44

55
import { statusByComponent } from '~/_state/component-statuses';
66

7+
<StatusBanner status={statusByComponent.styled.Select} />
8+
79
# Select
810

9-
With a gentle click, you unveil a buffet of options; the Qwik UI Styled select is where your choice is the guest of honor, awaiting its moment to shine
11+
Displays a list of options for the user to pick from — triggered by a button.
1012

11-
<StatusBanner status={statusByComponent.styled.Select} />
13+
<Showcase name="hero" />
14+
15+
## Installation
16+
17+
### Run the following cli command or copy/paste the component code into your project
18+
19+
```sh
20+
qwik-ui add select
21+
```
22+
23+
```tsx
24+
import { PropsOf, Slot, component$ } from '@builder.io/qwik';
25+
import { Select as HeadlessSelect } from '@qwik-ui/headless';
26+
import { cn } from '@qwik-ui/utils';
27+
import { LuCheck, LuChevronDown } from '@qwikest/icons/lucide';
28+
29+
const Root = (props: PropsOf<typeof HeadlessSelect.Root>) => (
30+
<HeadlessSelect.Root
31+
{...props}
32+
selectItemComponent={Item}
33+
selectItemLabelComponent={ItemLabel}
34+
selectLabelComponent={Label}
35+
/>
36+
);
37+
38+
const Label = component$<PropsOf<typeof HeadlessSelect.Label>>(({ ...props }) => {
39+
return (
40+
<>
41+
<HeadlessSelect.Label
42+
{...props}
43+
class={cn('px-2 py-1.5 text-sm font-semibold', props.class)}
44+
>
45+
<Slot />
46+
</HeadlessSelect.Label>
47+
</>
48+
);
49+
});
50+
51+
const Trigger = component$<PropsOf<typeof HeadlessSelect.Trigger>>(({ ...props }) => {
52+
return (
53+
<>
54+
<HeadlessSelect.Trigger
55+
{...props}
56+
class={cn(
57+
'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',
58+
props.class,
59+
)}
60+
>
61+
<Slot />
62+
<LuChevronDown class="h-4 w-4 opacity-50" />
63+
</HeadlessSelect.Trigger>
64+
</>
65+
);
66+
});
67+
68+
const DisplayText = HeadlessSelect.DisplayText;
69+
70+
const Popover = component$<PropsOf<typeof HeadlessSelect.Popover>>(({ ...props }) => {
71+
return (
72+
<>
73+
<HeadlessSelect.Popover
74+
{...props}
75+
class={cn(
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',
77+
// 'overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md',
78+
props.class,
79+
)}
80+
>
81+
<Slot />
82+
</HeadlessSelect.Popover>
83+
</>
84+
);
85+
});
86+
87+
type ListboxProps = PropsOf<typeof HeadlessSelect.Listbox>;
88+
const Listbox = component$<ListboxProps>(({ ...props }) => {
89+
return (
90+
<>
91+
<HeadlessSelect.Listbox
92+
{...props}
93+
class={cn(
94+
'relative z-50 max-h-96 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md',
95+
props.class,
96+
)}
97+
>
98+
<Slot />
99+
</HeadlessSelect.Listbox>
100+
</>
101+
);
102+
});
103+
104+
const Group = HeadlessSelect.Group;
105+
106+
const GroupLabel = HeadlessSelect.GroupLabel;
107+
108+
const Item = component$<PropsOf<typeof HeadlessSelect.Item>>(({ ...props }) => {
109+
return (
110+
<HeadlessSelect.Item
111+
{...props}
112+
class={cn(
113+
'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',
115+
props.class,
116+
)}
117+
>
118+
<Slot />
119+
</HeadlessSelect.Item>
120+
);
121+
});
122+
123+
const ItemIndicator = component$<PropsOf<typeof HeadlessSelect.ItemIndicator>>(
124+
({ ...props }) => {
125+
return (
126+
<span class="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
127+
<HeadlessSelect.ItemIndicator {...props}>
128+
<LuCheck class="h-4 w-4" />
129+
</HeadlessSelect.ItemIndicator>
130+
</span>
131+
);
132+
},
133+
);
134+
135+
const ItemLabel = component$<PropsOf<typeof HeadlessSelect.ItemLabel>>(({ ...props }) => {
136+
return (
137+
<HeadlessSelect.ItemLabel {...props}>
138+
<Slot />
139+
</HeadlessSelect.ItemLabel>
140+
);
141+
});
142+
143+
export const Select = {
144+
Root,
145+
Label,
146+
Trigger,
147+
DisplayText,
148+
Popover,
149+
Listbox,
150+
Group,
151+
GroupLabel,
152+
Item,
153+
ItemIndicator,
154+
ItemLabel,
155+
};
156+
```

package.json

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -40,35 +40,35 @@
4040
},
4141
"packageManager": "[email protected]",
4242
"devDependencies": {
43-
"@axe-core/playwright": "^4.9.0",
44-
"@builder.io/qwik": "^1.5.4",
45-
"@builder.io/qwik-city": "^1.5.4",
43+
"@axe-core/playwright": "^4.9.1",
44+
"@builder.io/qwik": "^1.5.5",
45+
"@builder.io/qwik-city": "^1.5.5",
4646
"@builder.io/qwik-react": "^0.5.4",
47-
"@changesets/cli": "^2.27.2",
47+
"@changesets/cli": "^2.27.3",
4848
"@changesets/get-github-info": "^0.6.0",
4949
"@changesets/types": "^6.0.0",
5050
"@clack/prompts": "^0.7.0",
5151
"@cypress/code-coverage": "^3.12.39",
52-
"@cypress/vite-dev-server": "^5.0.7",
52+
"@cypress/vite-dev-server": "^5.1.0",
5353
"@floating-ui/core": "^1.6.2",
5454
"@floating-ui/dom": "^1.6.5",
5555
"@fontsource-variable/inter": "^5.0.18",
5656
"@img/sharp-linux-x64": "^0.33.4",
5757
"@jscutlery/semver": "^4.2.0",
58-
"@k11r/nx-cloudflare-wrangler": "^3.0.0-feat-sst-upgrade.1",
58+
"@k11r/nx-cloudflare-wrangler": "3.0.0-feat-sst-upgrade.1",
5959
"@modular-forms/qwik": "^0.24.0",
60-
"@nx/cypress": "^19.0.4",
61-
"@nx/devkit": "^19.0.4",
62-
"@nx/eslint": "^19.0.4",
63-
"@nx/eslint-plugin": "^19.0.4",
64-
"@nx/jest": "^19.0.4",
65-
"@nx/js": "^19.0.4",
66-
"@nx/playwright": "^19.0.4",
67-
"@nx/plugin": "^19.0.4",
68-
"@nx/vite": "^19.0.4",
69-
"@nx/workspace": "^19.0.4",
60+
"@nx/cypress": "^19.0.8",
61+
"@nx/devkit": "^19.0.8",
62+
"@nx/eslint": "^19.0.8",
63+
"@nx/eslint-plugin": "^19.0.8",
64+
"@nx/jest": "^19.0.8",
65+
"@nx/js": "^19.0.8",
66+
"@nx/playwright": "^19.0.8",
67+
"@nx/plugin": "^19.0.8",
68+
"@nx/vite": "^19.0.8",
69+
"@nx/workspace": "^19.0.8",
7070
"@oddbird/popover-polyfill": "0.4.3",
71-
"@playwright/test": "^1.44.0",
71+
"@playwright/test": "^1.44.1",
7272
"@qwikest/icons": "^0.0.13",
7373
"@radix-ui/react-scroll-area": "^1.0.5",
7474
"@shikijs/transformers": "^1.6.0",
@@ -105,8 +105,8 @@
105105
"eslint": "^8.57.0",
106106
"eslint-config-prettier": "^9.1.0",
107107
"eslint-plugin-cypress": "^3.2.0",
108-
"eslint-plugin-playwright": "^1.6.1",
109-
"eslint-plugin-qwik": "^1.5.4",
108+
"eslint-plugin-playwright": "^1.6.2",
109+
"eslint-plugin-qwik": "^1.5.5",
110110
"focus-trap": "7.5.4",
111111
"husky": "^9.0.11",
112112
"jest": "^29.7.0",
@@ -121,7 +121,7 @@
121121
"prettier": "^3.2.5",
122122
"prettier-plugin-tailwindcss": "^0.5.14",
123123
"pretty-quick": "^4.0.0",
124-
"qwik-nx": "^2.2.1",
124+
"qwik-nx": "^2.3.0",
125125
"qwik-themes": "^0.2.0",
126126
"react": "18.3.1",
127127
"react-dom": "18.3.1",
@@ -132,7 +132,7 @@
132132
"tailwind-merge": "^2.3.0",
133133
"tailwindcss": "^3.4.3",
134134
"tailwindcss-animate": "^1.0.7",
135-
"ts-jest": "^29.1.2",
135+
"ts-jest": "^29.1.3",
136136
"tslib": "^2.6.2",
137137
"typescript": "5.4.5",
138138
"undici": "5.28.4",
@@ -146,7 +146,7 @@
146146
"vite-plugin-static-copy": "1.0.4",
147147
"vite-tsconfig-paths": "4.3.2",
148148
"vitest": "^1.6.0",
149-
"wrangler": "^3.57.0",
149+
"wrangler": "^3.57.1",
150150
"yargs": "^17.7.2"
151151
},
152152
"config": {
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/components-registry.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@
8585
"componentFolder": "radio-group",
8686
"files": ["radio-group.tsx"]
8787
},
88+
{
89+
"displayName": "Select",
90+
"type": "select",
91+
"componentFolder": "select",
92+
"files": ["select.tsx"]
93+
},
8894
{
8995
"displayName": "Separator",
9096
"type": "separator",

0 commit comments

Comments
 (0)