Skip to content

Commit 9d0a909

Browse files
Merge pull request #445 from thejackshelton/popover-combobox
Feat: Popover API support across browsers
2 parents 69da55a + d231c20 commit 9d0a909

File tree

86 files changed

+2017
-1022
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+2017
-1022
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const statusByComponent: ComponentKitsStatuses = {
4646
Dialog: ComponentStatus.Planned,
4747
Modal: ComponentStatus.Beta,
4848
Pagination: ComponentStatus.Draft,
49-
Popover: ComponentStatus.Draft,
49+
Popover: ComponentStatus.Beta,
5050
Select: ComponentStatus.Draft,
5151
Separator: ComponentStatus.Beta,
5252
Tabs: ComponentStatus.Beta,

apps/website/src/components/api-table/api-table.tsx

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { component$ } from '@builder.io/qwik';
2-
import { Popover, PopoverContent, PopoverTrigger } from '@qwik-ui/headless';
2+
import { InfoPopup } from '../info-popup/info-popup';
33
type APITableProps = {
44
propDescriptors: {
55
name: string;
@@ -32,40 +32,12 @@ export const APITable = component$(({ propDescriptors }: APITableProps) => {
3232
</code>
3333
</td>
3434
<td class="py-3">
35-
<span class="flex items-center">
35+
<div class="flex items-center gap-2">
3636
<code class="rounded-md border border-b-2 px-2">
3737
{propDescriptor.type}
3838
</code>
39-
{propDescriptor.info && (
40-
<Popover placement="top">
41-
<PopoverContent>
42-
<div class="shadow-light-medium dark:shadow-dark-high bg-background text-md mb-2 max-w-xs rounded-lg border border-b-2 px-3 py-2 font-medium sm:w-max">
43-
{propDescriptor?.info}
44-
</div>
45-
</PopoverContent>
46-
<PopoverTrigger>
47-
<div class="mx-2 mt-2 rounded-xl p-1">
48-
<svg
49-
width="15"
50-
height="15"
51-
viewBox="0 0 15 15"
52-
fill="none"
53-
xmlns="http://www.w3.org/2000/svg"
54-
aria-hidden="true"
55-
focusable="false"
56-
>
57-
<path
58-
d="M7.49991 0.876892C3.84222 0.876892 0.877075 3.84204 0.877075 7.49972C0.877075 11.1574 3.84222 14.1226 7.49991 14.1226C11.1576 14.1226 14.1227 11.1574 14.1227 7.49972C14.1227 3.84204 11.1576 0.876892 7.49991 0.876892ZM1.82707 7.49972C1.82707 4.36671 4.36689 1.82689 7.49991 1.82689C10.6329 1.82689 13.1727 4.36671 13.1727 7.49972C13.1727 10.6327 10.6329 13.1726 7.49991 13.1726C4.36689 13.1726 1.82707 10.6327 1.82707 7.49972ZM8.24992 4.49999C8.24992 4.9142 7.91413 5.24999 7.49992 5.24999C7.08571 5.24999 6.74992 4.9142 6.74992 4.49999C6.74992 4.08577 7.08571 3.74999 7.49992 3.74999C7.91413 3.74999 8.24992 4.08577 8.24992 4.49999ZM6.00003 5.99999H6.50003H7.50003C7.77618 5.99999 8.00003 6.22384 8.00003 6.49999V9.99999H8.50003H9.00003V11H8.50003H7.50003H6.50003H6.00003V9.99999H6.50003H7.00003V6.99999H6.50003H6.00003V5.99999Z"
59-
fill="currentColor"
60-
fill-rule="evenodd"
61-
clip-rule="evenodd"
62-
></path>
63-
</svg>
64-
</div>
65-
</PopoverTrigger>
66-
</Popover>
67-
)}
68-
</span>
39+
{propDescriptor.info && <InfoPopup info={propDescriptor.info} />}
40+
</div>
6941
</td>
7042
<td class="py-3 align-baseline">
7143
<div class="prose prose-sm prose-docs-table px-2">
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { component$, useId, useSignal, useStyles$ } from '@builder.io/qwik';
2+
import { Popover, PopoverTrigger } from '@qwik-ui/headless';
3+
4+
type InfoProps = {
5+
info: string;
6+
};
7+
8+
export const InfoPopup = component$((props: InfoProps) => {
9+
const popoverTableId = useId();
10+
const triggerRef = useSignal<HTMLButtonElement>();
11+
const popoverRef = useSignal<HTMLElement>();
12+
13+
useStyles$(`
14+
.fade-info {
15+
transition: opacity 0.35s, display 0.35s, overlay 0.35s;
16+
transition-behavior: allow-discrete;
17+
opacity: 0;
18+
}
19+
20+
.popover-showing {
21+
opacity: 1;
22+
}
23+
24+
.popover-closing {
25+
opacity: 0;
26+
}
27+
`);
28+
29+
return (
30+
<>
31+
<PopoverTrigger
32+
ref={triggerRef}
33+
popoverTargetAction="show"
34+
popovertarget={popoverTableId}
35+
class="flex items-center justify-center"
36+
>
37+
<div class="rounded-full p-1 hover:bg-slate-300 hover:bg-opacity-50">
38+
<svg
39+
width="16"
40+
height="16"
41+
viewBox="0 0 15 15"
42+
fill="none"
43+
xmlns="http://www.w3.org/2000/svg"
44+
aria-hidden="true"
45+
focusable="false"
46+
>
47+
<path
48+
d="M7.49991 0.876892C3.84222 0.876892 0.877075 3.84204 0.877075 7.49972C0.877075 11.1574 3.84222 14.1226 7.49991 14.1226C11.1576 14.1226 14.1227 11.1574 14.1227 7.49972C14.1227 3.84204 11.1576 0.876892 7.49991 0.876892ZM1.82707 7.49972C1.82707 4.36671 4.36689 1.82689 7.49991 1.82689C10.6329 1.82689 13.1727 4.36671 13.1727 7.49972C13.1727 10.6327 10.6329 13.1726 7.49991 13.1726C4.36689 13.1726 1.82707 10.6327 1.82707 7.49972ZM8.24992 4.49999C8.24992 4.9142 7.91413 5.24999 7.49992 5.24999C7.08571 5.24999 6.74992 4.9142 6.74992 4.49999C6.74992 4.08577 7.08571 3.74999 7.49992 3.74999C7.91413 3.74999 8.24992 4.08577 8.24992 4.49999ZM6.00003 5.99999H6.50003H7.50003C7.77618 5.99999 8.00003 6.22384 8.00003 6.49999V9.99999H8.50003H9.00003V11H8.50003H7.50003H6.50003H6.00003V9.99999H6.50003H7.00003V6.99999H6.50003H6.00003V5.99999Z"
49+
fill="currentColor"
50+
fill-rule="evenodd"
51+
clip-rule="evenodd"
52+
></path>
53+
</svg>
54+
</div>
55+
</PopoverTrigger>
56+
57+
<Popover
58+
ref={popoverRef}
59+
anchorRef={triggerRef}
60+
floating={true}
61+
flip={false}
62+
placement="top"
63+
gutter={4}
64+
id={popoverTableId}
65+
class="fade-info listbox rounded-md bg-transparent"
66+
>
67+
<div class="shadow-light-medium bg-qwikui-blue-50 dark:shadow-dark-high text-md border-qwikui-blue-500 dark:border-qwikui-purple-500 dark:bg-qwikui-purple-100 bg-primary mb-2 max-w-xs rounded-lg border-[1px] border-b-2 px-3 py-2 font-[500] text-slate-950 sm:w-max">
68+
{props.info}
69+
</div>
70+
</Popover>
71+
</>
72+
);
73+
});

apps/website/src/components/preview-code-example/preview-code-example-tabs-deprecated.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export const PreviewCodeExampleTabsDeprecated = component$((props: { code?: stri
2020
selectedClassName="previewCodeExampleSelectedTab"
2121
>
2222
<TabList class="bg-qwikui-blue-700 dark:bg-qwikui-purple-800 border-qwikui-blue-300 dark:border-qwikui-purple-200 shadow-light-medium dark:shadow-dark-medium flex rounded-t-xl border-[1.5px] border-b-0 text-white">
23-
<Tab class="hover:bg-qwikui-blue-500 dark:hover:bg-qwikui-purple-600 text-outline-lg min-h-[44px] rounded-tl-[.625rem] px-4 px-[28px] py-2">
23+
<Tab class="hover:bg-qwikui-blue-500 dark:hover:bg-qwikui-purple-600 text-outline-lg min-h-[44px] rounded-tl-[.625rem] px-[28px] py-2">
2424
Preview
2525
</Tab>
2626
<Tab class="hover:bg-qwikui-blue-500 dark:hover:bg-qwikui-purple-600 text-outline-lg min-h-[44px] px-4 px-[28px] py-2">

apps/website/src/routes/docs/fluffy/popover/_index.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import { component$, useSignal } from '@builder.io/qwik';
2-
import { Popover, PopoverContent, PopoverTrigger } from '@qwik-ui/headless';
32

4-
import { Button, Card, CardBody, CardTitle } from '@qwik-ui/tailwind';
3+
import { Card, CardBody, CardTitle } from '@qwik-ui/tailwind';
54

65
export default component$(() => {
76
const controlledPopover = useSignal<boolean>(true);
87

98
return (
109
<>
11-
<h2>This is the documentation for the Popover</h2>
10+
{/* <h2>This is the documentation for the Popover</h2>
1211
1312
<h1 class="mt-8">Examples</h1>
1413
<Popover placement="top">
@@ -165,7 +164,7 @@ export default component$(() => {
165164
166165
<Button onClick$={() => (controlledPopover.value = true)}>
167166
OPEN THE POPOVER ABOVE
168-
</Button>
167+
</Button> */}
169168
</>
170169
);
171170
});

apps/website/src/routes/docs/headless/breadcrumb/BreadcrumbWrapper.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { component$, HTMLAttributes, Slot, useStyles$ } from '@builder.io/qwik';
1+
import { component$, QwikIntrinsicElements, Slot, useStyles$ } from '@builder.io/qwik';
22
import style from './BreadcrumbWrapper.css?inline';
33

4-
interface BreadcrumbWrapperProps extends HTMLAttributes<HTMLElement> {
4+
type BreadcrumbWrapperProps = QwikIntrinsicElements['div'] & {
55
title?: string;
6-
}
6+
};
77

88
export default component$(({ title, ...rest }: BreadcrumbWrapperProps) => {
99
useStyles$(style);

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
ComboboxLabel,
77
ComboboxListbox,
88
ComboboxOption,
9-
ComboboxPortal,
9+
ComboboxPopover,
1010
ComboboxTrigger,
1111
ResolvedOption,
1212
} from '@qwik-ui/headless';
@@ -38,11 +38,9 @@ export const ContextChild = component$(() => {
3838
<ComboboxIcon class="stroke-foreground transition-transform duration-[450ms] group-aria-expanded:-rotate-180" />
3939
</ComboboxTrigger>
4040
</ComboboxControl>
41-
<ComboboxPortal>
41+
<ComboboxPopover flip={true} gutter={8}>
4242
<ComboboxListbox
43-
flip={true}
44-
gutter={8}
45-
class="bg-background w-44 rounded-sm border px-4 py-2"
43+
class="w-44 rounded-sm border-[1px] border-slate-400 bg-slate-900 px-4 py-2"
4644
optionRenderer$={(option: ResolvedOption, index: number) => (
4745
<ComboboxOption
4846
index={index}
@@ -55,7 +53,7 @@ export const ContextChild = component$(() => {
5553
</ComboboxOption>
5654
)}
5755
/>
58-
</ComboboxPortal>
56+
</ComboboxPopover>
5957
</Combobox>
6058
);
6159
});

apps/website/src/routes/docs/headless/combobox/examples/custom-filter.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
ComboboxLabel,
77
ComboboxListbox,
88
ComboboxOption,
9-
ComboboxPortal,
9+
ComboboxPopover,
1010
ComboboxTrigger,
1111
ResolvedOption,
1212
} from '@qwik-ui/headless';
@@ -47,11 +47,9 @@ export default component$(() => {
4747
<ComboboxIcon class="stroke-foreground transition-transform duration-[450ms] group-aria-expanded:-rotate-180" />
4848
</ComboboxTrigger>
4949
</ComboboxControl>
50-
<ComboboxPortal>
50+
<ComboboxPopover flip={true} gutter={8}>
5151
<ComboboxListbox
52-
flip={true}
53-
gutter={8}
54-
class="bg-background w-44 rounded-sm border px-4 py-2"
52+
class="w-44 rounded-sm border-[1px] border-slate-400 bg-slate-900 px-4 py-2"
5553
optionRenderer$={(option: ResolvedOption, index: number) => (
5654
<ComboboxOption
5755
key={option.key}
@@ -63,7 +61,7 @@ export default component$(() => {
6361
</ComboboxOption>
6462
)}
6563
/>
66-
</ComboboxPortal>
64+
</ComboboxPopover>
6765
</Combobox>
6866
);
6967
});

apps/website/src/routes/docs/headless/combobox/examples/custom-keys.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
ComboboxLabel,
77
ComboboxListbox,
88
ComboboxOption,
9-
ComboboxPortal,
9+
ComboboxPopover,
1010
ComboboxTrigger,
1111
ResolvedOption,
1212
} from '@qwik-ui/headless';
@@ -58,11 +58,9 @@ export default component$(() => {
5858
<ComboboxIcon class="stroke-foreground transition-transform duration-[450ms] group-aria-expanded:-rotate-180" />
5959
</ComboboxTrigger>
6060
</ComboboxControl>
61-
<ComboboxPortal>
61+
<ComboboxPopover flip={true} gutter={8}>
6262
<ComboboxListbox
63-
flip={true}
64-
gutter={8}
65-
class="bg-background w-44 rounded-sm border px-4 py-2"
63+
class="w-44 rounded-sm border-[1px] border-slate-400 bg-slate-900 px-4 py-2"
6664
optionRenderer$={(option: ResolvedOption, index: number) => {
6765
const pokemonOption = option.option as Pokemon;
6866
return (
@@ -86,7 +84,7 @@ export default component$(() => {
8684
);
8785
}}
8886
/>
89-
</ComboboxPortal>
87+
</ComboboxPopover>
9088
</Combobox>
9189
</div>
9290
);

apps/website/src/routes/docs/headless/combobox/examples/default-label.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
ComboboxLabel,
77
ComboboxListbox,
88
ComboboxOption,
9-
ComboboxPortal,
9+
ComboboxPopover,
1010
ComboboxTrigger,
1111
ResolvedOption,
1212
} from '@qwik-ui/headless';
@@ -25,11 +25,9 @@ export default component$(() => {
2525
<ComboboxIcon class="stroke-foreground transition-transform duration-[450ms] group-aria-expanded:-rotate-180" />
2626
</ComboboxTrigger>
2727
</ComboboxControl>
28-
<ComboboxPortal>
28+
<ComboboxPopover gutter={8} hide="escaped">
2929
<ComboboxListbox
30-
gutter={8}
31-
class="bg-background w-44 rounded-sm border px-4 py-2"
32-
hide="escaped"
30+
class="w-44 rounded-sm border-[1px] border-slate-400 bg-slate-900 px-4 py-2"
3331
optionRenderer$={(option: ResolvedOption, index: number) => (
3432
<ComboboxOption
3533
key={option.key}
@@ -41,7 +39,7 @@ export default component$(() => {
4139
</ComboboxOption>
4240
)}
4341
/>
44-
</ComboboxPortal>
42+
</ComboboxPopover>
4543
</Combobox>
4644
);
4745
});

0 commit comments

Comments
 (0)