Skip to content

Commit ea5ba0e

Browse files
Gregor WoiwodeGregOnNet
authored andcommitted
fix(dialog): close dialog on backdrop click
1 parent cc26112 commit ea5ba0e

File tree

8 files changed

+267
-21
lines changed

8 files changed

+267
-21
lines changed

apps/website/src/routes/docs/headless/(components)/dialog/examples.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export const Example01 = component$(() => {
1010
<Dialog.Trigger>
1111
<button>Open Dialog</button>
1212
</Dialog.Trigger>
13-
<Dialog.Portal>Hallo Welt</Dialog.Portal>
13+
<Dialog.Portal>Hello World</Dialog.Portal>
1414
</Dialog.Root>
1515
</div>
1616

apps/website/src/routes/docs/headless/(components)/dialog/index.mdx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ import { KeyboardInteractionTable } from '../../../../../components/keyboard-int
2020
</Dialog.Trigger>
2121
<Dialog.Portal>
2222
<p>
23-
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus
24-
aliquid architecto delectus deleniti dolor
23+
Hello World
2524
</p>
2625
</Dialog.Portal>
2726

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import { component$, Slot } from '@builder.io/qwik';
2+
import {
3+
Accordion,
4+
AccordionItem,
5+
Button,
6+
Checkbox,
7+
Dialog,
8+
} from '@qwik-ui/tailwind';
9+
import { PreviewCodeExample } from '../../../../../components/preview-code-example/preview-code-example';
10+
11+
export const Example01 = component$(() => {
12+
return (
13+
<PreviewCodeExample>
14+
<div q:slot="actualComponent">
15+
<Dialog.Root>
16+
<Dialog.Trigger>
17+
<button>Open Dialog</button>
18+
</Dialog.Trigger>
19+
<Dialog.Portal>
20+
Hello World
21+
<Dialog.Close>
22+
<Button>Close</Button>
23+
</Dialog.Close>
24+
</Dialog.Portal>
25+
</Dialog.Root>
26+
</div>
27+
28+
<div q:slot="codeExample">
29+
<Slot />
30+
</div>
31+
</PreviewCodeExample>
32+
);
33+
});
34+
35+
export const Example02 = component$(() => {
36+
return (
37+
<PreviewCodeExample>
38+
<div q:slot="actualComponent">
39+
<Accordion class="bg-slate-100 dark:bg-gray-700 w-80 rounded-xl border-slate-200 dark:border-gray-600 border-[1px] overflow-hidden">
40+
<AccordionItem
41+
class="px-4 py-2 w-full hover:bg-slate-300 dark:hover:bg-gray-800 border-slate-200 dark:border-gray-600 border-[1px] text-left"
42+
label="Is Qwik production-ready?"
43+
>
44+
<p class="bg-slate-200 dark:bg-gray-900 p-4">
45+
Yes, Qwik just hit a major milestone and launched v1.0! All API
46+
features are considered stable. Start building the future, today!
47+
</p>
48+
</AccordionItem>
49+
<AccordionItem
50+
class="px-4 py-2 w-full hover:bg-slate-300 dark:hover:bg-gray-800 border-slate-200 dark:border-gray-600 border-[1px] text-left"
51+
label="Is there a UI library I can use with Qwik?"
52+
>
53+
<p class="bg-slate-200 dark:bg-gray-900 p-4">
54+
You're looking at one right now!
55+
</p>
56+
</AccordionItem>
57+
<AccordionItem
58+
class="px-4 py-2 w-full hover:bg-slate-300 dark:hover:bg-gray-800 border-slate-200 dark:border-gray-600 border-[1px] text-left"
59+
label="How can I contribute to Qwik UI?"
60+
>
61+
<p class="bg-slate-200 dark:bg-gray-900 p-4">
62+
We're glad you asked. Come join us at the Qwikifiers Discord
63+
server or find the{` `}
64+
<a
65+
class="text-[var(--qwik-light-blue)] inline"
66+
href="https://github.com/qwikifiers/qwik-ui"
67+
>
68+
Qwik UI repository
69+
</a>
70+
{` `}
71+
on GitHub!
72+
</p>
73+
</AccordionItem>
74+
</Accordion>
75+
</div>
76+
77+
<div q:slot="codeExample">
78+
<Slot />
79+
</div>
80+
</PreviewCodeExample>
81+
);
82+
});
83+
84+
export const Example03 = component$(() => {
85+
return (
86+
<PreviewCodeExample>
87+
<div q:slot="actualComponent">
88+
<Accordion class="mt-4 p-4 bg-slate-800">
89+
<AccordionItem label="Availability">
90+
<ul>
91+
<li>
92+
<Checkbox.Label class="flex" for="in-stock">
93+
<Checkbox.Root id="in-stock" />
94+
In stock
95+
</Checkbox.Label>
96+
</li>
97+
<li>
98+
<Checkbox.Label class="flex" for="out-of-stock">
99+
<Checkbox.Root id="out-of-stock" />
100+
Out of stock
101+
</Checkbox.Label>
102+
</li>
103+
<li>
104+
<Checkbox.Label class="flex" for="coming-soon">
105+
<Checkbox.Root id="coming-soon" />
106+
Coming soon
107+
</Checkbox.Label>
108+
</li>
109+
</ul>
110+
</AccordionItem>
111+
<AccordionItem label="Promotions">
112+
<ul>
113+
<li>
114+
<Checkbox.Label class="flex" for="fifty-off">
115+
<Checkbox.Root id="fifty-off" />
116+
50% off on selected products
117+
</Checkbox.Label>
118+
</li>
119+
<li>
120+
<Checkbox.Label class="flex" for="winter-special">
121+
<Checkbox.Root id="winter-special" />
122+
Winter specials
123+
</Checkbox.Label>
124+
</li>
125+
</ul>
126+
</AccordionItem>
127+
<AccordionItem label="Category">
128+
<ul>
129+
<li>
130+
<Checkbox.Label class="flex" for="books">
131+
<Checkbox.Root id="books" />
132+
Books
133+
</Checkbox.Label>
134+
</li>
135+
<li>
136+
<Checkbox.Label class="flex" for="stationery">
137+
<Checkbox.Root id="stationery" />
138+
Stationery
139+
</Checkbox.Label>
140+
</li>
141+
<li>
142+
<Checkbox.Label class="flex" for="storage">
143+
<Checkbox.Root id="storage" />
144+
Storage
145+
</Checkbox.Label>
146+
</li>
147+
</ul>
148+
</AccordionItem>
149+
</Accordion>
150+
</div>
151+
152+
<div q:slot="codeExample">
153+
<Slot />
154+
</div>
155+
</PreviewCodeExample>
156+
);
157+
});
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
title: Qwik UI | Dialog
3+
---
4+
5+
import { Dialog, Button } from '@qwik-ui/tailwind';
6+
import { Example01 } from './examples';
7+
import { KeyboardInteractionTable } from '../../../../../components/keyboard-interaction-table/keyboard-interaction-table';
8+
9+
# Dialog
10+
11+
#### A window overlaid on either the primary window or another dialog window, rendering the content underneath inert. ([Definition comes from Radix-UI](https://www.radix-ui.com/docs/primitives/components/dialog))
12+
13+
{' '}
14+
15+
<Example01>
16+
```tsx
17+
<Dialog.Root>
18+
<Dialog.Trigger>
19+
<button>Open Dialog</button>
20+
</Dialog.Trigger>
21+
<Dialog.Portal>
22+
<p>Hello World</p>
23+
<Dialog.Close>
24+
<Button>Close</Button>
25+
</Dialog.Close>
26+
</Dialog.Portal>
27+
</Dialog.Root>
28+
```
29+
</Example01>
30+
31+
## Accessibility
32+
33+
### Keyboard interaction
34+
35+
<KeyboardInteractionTable
36+
keyDescriptors={[
37+
{
38+
keyTitle: 'Escape',
39+
description: 'Closes the dialog.',
40+
},
41+
]}
42+
/>

packages/kit-headless/src/components/dialog/dialog.spec.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ describe('Dialog', () => {
99
<button>Open</button>
1010
</Dialog.Trigger>
1111
<Dialog.Portal>
12+
{/* Dialog.Header */}
13+
{/* Dialog.Content */}
14+
{/* Dialog.Actions/Footer */}
1215
<h2 data-test="dialog-title">Hello World!</h2>
1316
</Dialog.Portal>
1417
</Dialog.Root>

packages/kit-headless/src/components/dialog/dialog.tsx

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
$,
33
QRL,
4+
QwikIntrinsicElements,
45
QwikMouseEvent,
56
Signal,
67
Slot,
@@ -66,13 +67,19 @@ export const Root = component$(() => {
6667
});
6768

6869
const closeOnDialogClick$ = $(
69-
(
70-
event: QwikMouseEvent<HTMLDialogElement, MouseEvent>,
71-
element: HTMLDialogElement
72-
) => {
73-
if (event.target !== element) return;
74-
75-
return closeDialog$();
70+
(event: QwikMouseEvent<HTMLDialogElement, MouseEvent>) => {
71+
const rect = (event.target as HTMLDialogElement).getBoundingClientRect();
72+
73+
if (
74+
rect.left > event.clientX ||
75+
rect.right < event.clientX ||
76+
rect.top > event.clientY ||
77+
rect.bottom < event.clientY
78+
) {
79+
return closeDialog$();
80+
}
81+
82+
return Promise.resolve();
7683
}
7784
);
7885

@@ -104,11 +111,32 @@ export const Trigger = component$(() => {
104111
);
105112
});
106113

107-
export const Portal = component$(() => {
114+
export const Close = component$(() => {
115+
const context = useContext(dialogContext);
116+
117+
useOn(
118+
'click',
119+
$(() => context.close())
120+
);
121+
122+
return (
123+
<div role="button">
124+
<Slot />
125+
</div>
126+
);
127+
});
128+
129+
type PortalProps = QwikIntrinsicElements['dialog'];
130+
131+
export const Portal = component$((props: PortalProps) => {
108132
const context = useContext(dialogContext);
109133

110134
return (
111-
<dialog ref={context.state.dialogRef} onClick$={context.closeOnDialogClick}>
135+
<dialog
136+
{...props}
137+
ref={context.state.dialogRef}
138+
onClick$={context.closeOnDialogClick}
139+
>
112140
<Slot />
113141
</dialog>
114142
);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Slot, component$ } from '@builder.io/qwik';
2+
import { Dialog } from '@qwik-ui/headless';
3+
4+
export const Root = Dialog.Root;
5+
6+
export const Trigger = Dialog.Trigger;
7+
8+
export const Close = Dialog.Close;
9+
10+
export const Portal = component$(() => {
11+
return (
12+
<Dialog.Portal class="bg-slate-900 rounded-md text-white">
13+
<Slot />
14+
</Dialog.Portal>
15+
);
16+
});

packages/kit-tailwind/src/index.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
export * from './components/accordion/accordion';
22
export * from './components/alert/alert';
33
export * from './components/badge/badge';
4-
export * from './components/button/button';
5-
export * from './components/progress/progress';
4+
export * from './components/breadcrumb';
65
export * from './components/button-group/button-group';
6+
export * from './components/button/button';
77
export * from './components/card';
8+
export * from './components/checkbox/checkbox';
89
export * from './components/collapse/collapse';
10+
export * as Dialog from './components/dialog/dialog';
911
export * from './components/drawer/drawer';
10-
export * from './components/spinner/spinner';
12+
export * from './components/navigation-bar/navigation-bar';
13+
export * from './components/pagination/pagination';
1114
export * from './components/popover/popover';
15+
export * from './components/progress/progress';
1216
export * from './components/rating/rating';
17+
export * from './components/ratio/radio';
18+
export * from './components/slider/slider';
19+
export * from './components/spinner/spinner';
1320
export * from './components/tabs';
1421
export * from './components/toast/toast';
1522
export * from './components/toggle/toggle';
1623
export * from './components/tooltip/tooltip';
17-
export * from './components/checkbox/checkbox';
18-
export * from './components/pagination/pagination';
19-
export * from './components/ratio/radio';
20-
export * from './components/slider/slider';
21-
export * from './components/breadcrumb';
22-
export * from './components/navigation-bar/navigation-bar';

0 commit comments

Comments
 (0)