Skip to content

Commit e9ccb07

Browse files
Merge pull request #702 from thejackshelton/feat/modal
Refactor: Modal
2 parents fe6d10b + c3ee42c commit e9ccb07

Some content is hidden

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

53 files changed

+1385
-1508
lines changed

.changeset/eight-spiders-brake.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
---
2+
'@qwik-ui/headless': patch
3+
---
4+
5+
fix: modal does not close unless the dialog backdrop is clicked (including dangling content)
6+
7+
fix: polyfilled popovers render correctly inside of modals.
8+
9+
fix: nested modals will now close the current modal when the backdrop is clicked.
10+
11+
fix: nested modals will now close the current modal when the escape key is pressed.
12+
13+
fix: select does not execute code until interaction (including core).
14+
15+
tests: larger test suite for modals.
16+
17+
deprecated: `ModalHeader`, `ModalContent`, `ModalFooter` have been deprecated, as they do not pose significant a11y advantages.
18+
19+
feat: Two new Modal component pieces. `ModalTitle` and `ModalDescription`. These help give our modal an accessible name and supporting description (optional).
20+
21+
feat: Modal now uses the following CSS as a default inside of an @layer
22+
23+
```css
24+
@layer qwik-ui {
25+
/* browsers automatically set an interesting max-width and max-height for dialogs
26+
https://twitter.com/t3dotgg/status/1774350919133691936
27+
*/
28+
dialog:modal {
29+
max-width: unset;
30+
max-height: unset;
31+
}
32+
}
33+
```
34+
35+
The default browser styles:
36+
37+
![alt text](image.png)
38+
39+
Make it difficult to style a dialog element full-screen, which has led to some confusion recently both in this repo and across the web. The above change strips the responsible browser styles from the dialog eleemnt (which is used by Qwik UI's modal component).
40+
41+
> For more info, feel free to check out the link in the code snippet above.
42+
43+
> Note: In the future, we intend to use the dot notation for the `Modal` component.
44+
45+
> Note: In the future, we intend to change the modal API to include a trigger. The proposed API is as follows:
46+
47+
### Syntax Proposal
48+
49+
```tsx
50+
<Modal.Root>
51+
<Modal.Trigger>Trigger</Modal.Trigger>
52+
<Modal.Panel>
53+
{/* This is the current <Modal /> */}
54+
<Modal.Title>Edit Profile</Modal.Title>
55+
<Modal.Description>You can update your profile here.</Modal.Description>
56+
</Modal.Panel>
57+
</Modal.Root>
58+
```
59+
60+
Let us know your thoughts on this potential API change in the Qwik UI discord!

.changeset/image.png

82.3 KB
Loading

.changeset/mighty-snails-exist.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@qwik-ui/headless': patch
3+
---
4+
5+
feat: deprecate `modal-showing` and `modal-closing` classes in favor of `data-open`, `data-closing`, and `data-closed` data attributes.
6+
7+
> These classes will still work at the moment, but will be removed in a near future release.

apps/website/src/components/navigation-docs/navigation-docs.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const DocsNavigation = component$(
4646
const location = useLocation();
4747

4848
return (
49-
<nav {...props} class={cn('flex-col gap-4 pb-6', props.class)}>
49+
<nav {...props} class={cn('navigation-docs flex-col gap-4 pb-6', props.class)}>
5050
{linksGroups?.map((group) => {
5151
return (
5252
<div class="px-6 pt-8" key={group.name}>

apps/website/src/global.css

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,11 +1240,19 @@
12401240

12411241
*::-webkit-scrollbar-thumb {
12421242
/* Thumb color */
1243-
background-color: var(--qwikui-slate-500);
1243+
background-color: hsla(var(--foreground) / 0.25);
12441244
border-radius: 0.5rem;
12451245
background-clip: padding-box;
1246-
border-left: 0.3rem solid transparent;
1247-
border-right: 0.3rem solid transparent;
1246+
border-left: 0.15rem solid transparent;
1247+
border-right: 0.15rem solid transparent;
1248+
}
1249+
1250+
.navigation-docs::-webkit-scrollbar-thumb {
1251+
background-color: hsla(var(--foreground) / 0.1);
1252+
}
1253+
1254+
.dark .navigation-docs::-webkit-scrollbar-thumb {
1255+
background-color: hsla(var(--foreground) / 0.2);
12481256
}
12491257

12501258
*::-webkit-scrollbar-corner {
@@ -1256,10 +1264,6 @@
12561264
border-left: 1px solid var(--qwikui-slate-300);
12571265
}
12581266

1259-
.dark *::-webkit-scrollbar-thumb {
1260-
background-color: var(--qwikui-slate-500);
1261-
}
1262-
12631267
.dark *::-webkit-scrollbar-track {
12641268
background: transparent;
12651269
border-left: 1px solid var(--qwikui-slate-800);
@@ -1272,7 +1276,7 @@
12721276
}
12731277

12741278
.code-example *::-webkit-scrollbar-thumb {
1275-
background: var(--qwikui-slate-500);
1279+
background-color: var(--qwikui-slate-600);
12761280
border-radius: 0.5rem;
12771281
background-clip: padding-box;
12781282
}
Lines changed: 14 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,27 @@
1-
import { PropsOf, component$, useSignal } from '@builder.io/qwik';
2-
import { Modal, ModalContent, ModalFooter, ModalHeader } from '@qwik-ui/headless';
1+
import { component$, useSignal } from '@builder.io/qwik';
2+
import { Modal, ModalTitle, ModalDescription } from '@qwik-ui/headless';
33

44
export default component$(() => {
55
const showSig = useSignal(false);
66

77
return (
88
<>
9-
<button
10-
onClick$={() => (showSig.value = true)}
11-
class="rounded-base border px-3 py-2 hover:bg-accent/80"
12-
>
9+
<button class="modal-trigger" onClick$={() => (showSig.value = true)}>
1310
Deactivate
1411
</button>
15-
<Modal
16-
alert
17-
bind:show={showSig}
18-
class="max-w-[25rem] rounded-base bg-background p-[28px] text-foreground shadow-md backdrop:backdrop-blur backdrop:backdrop-brightness-50 dark:backdrop:backdrop-brightness-100"
19-
>
20-
<ModalHeader>
21-
<h2 class="mb-2 text-lg font-bold">Deactive Account</h2>
22-
</ModalHeader>
23-
<ModalContent class="mb-2 pb-4 pt-2">
24-
<p class="leading-5">Are you sure you want to deactivate your account?</p>
25-
</ModalContent>
26-
<ModalFooter class="flex justify-end gap-4">
27-
<button
28-
class="rounded-base border border-none bg-muted px-4 py-[10px] text-muted-foreground outline-none ring-offset-background transition-colors hover:bg-accent/90 hover:text-accent-foreground focus:ring focus:ring-ring focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
29-
onClick$={() => (showSig.value = false)}
30-
>
31-
Cancel
32-
</button>
33-
<button
34-
class="bg-destructive focus:ring-destructive text-destructive-foreground focus-visible:destructive-foreground/90 rounded-base border border-none px-4 py-[10px] outline-none focus:ring focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2"
35-
onClick$={() => (showSig.value = false)}
36-
>
37-
Delete
38-
</button>
39-
</ModalFooter>
40-
<button
41-
onClick$={() => (showSig.value = false)}
42-
class="absolute right-6 top-[26px]"
43-
>
44-
<CloseIcon class="h-8 w-8" />
12+
<Modal alert class="modal" bind:show={showSig}>
13+
<ModalTitle>Deactive Account</ModalTitle>
14+
<ModalDescription>
15+
Are you sure you want to deactivate your account?
16+
</ModalDescription>
17+
<footer>
18+
<button onClick$={() => (showSig.value = false)}>Cancel</button>
19+
<button onClick$={() => (showSig.value = false)}>Delete</button>
20+
</footer>
21+
<button class="modal-close" onClick$={() => (showSig.value = false)}>
22+
+
4523
</button>
4624
</Modal>
4725
</>
4826
);
4927
});
50-
51-
export function CloseIcon(props: PropsOf<'svg'>, key: string) {
52-
return (
53-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props} key={key}>
54-
<path
55-
fill="currentColor"
56-
d="m12 13.4l2.9 2.9q.275.275.7.275t.7-.275q.275-.275.275-.7t-.275-.7L13.4 12l2.9-2.9q.275-.275.275-.7t-.275-.7q-.275-.275-.7-.275t-.7.275L12 10.6L9.1 7.7q-.275-.275-.7-.275t-.7.275q-.275.275-.275.7t.275.7l2.9 2.9l-2.9 2.9q-.275.275-.275.7t.275.7q.275.275.7.275t.7-.275l2.9-2.9Zm0 8.6q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22Zm0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20Zm0-8Z"
57-
></path>
58-
</svg>
59-
);
60-
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { component$, useSignal, useStyles$ } from '@builder.io/qwik';
2+
import { Modal, ModalTitle, ModalDescription, Label } from '@qwik-ui/headless';
3+
import styles from '../snippets/animation.css?inline';
4+
5+
export default component$(() => {
6+
useStyles$(styles);
7+
const isOpen = useSignal(false);
8+
9+
return (
10+
<div class="modal-container">
11+
<button class="modal-trigger" onClick$={() => (isOpen.value = true)}>
12+
Open Modal
13+
</button>
14+
<Modal class="modal modal-animation" bind:show={isOpen}>
15+
<ModalTitle>Edit Profile</ModalTitle>
16+
<ModalDescription>
17+
You can update your profile here. Hit the save button when finished.
18+
</ModalDescription>
19+
<Label>
20+
Name
21+
<input type="text" placeholder="John Doe" />
22+
</Label>
23+
<Label>
24+
Email
25+
<input type="text" placeholder="[email protected]" />
26+
</Label>
27+
<footer>
28+
<button onClick$={() => (isOpen.value = false)}>Cancel</button>
29+
<button onClick$={() => (isOpen.value = false)}>Save Changes</button>
30+
</footer>
31+
</Modal>
32+
</div>
33+
);
34+
});

apps/website/src/routes/docs/headless/modal/examples/animation.tsx

Lines changed: 0 additions & 83 deletions
This file was deleted.

0 commit comments

Comments
 (0)