Skip to content

Commit 7978a8e

Browse files
fix(animations): animations work now
n
1 parent fccf147 commit 7978a8e

File tree

4 files changed

+209
-15
lines changed

4 files changed

+209
-15
lines changed

apps/website/src/routes/docs/headless/popover/examples/listbox-animation.tsx

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { component$, useSignal } from '@builder.io/qwik';
1+
import { component$, useSignal, useStyles$ } from '@builder.io/qwik';
22
import {
33
Combobox,
44
ComboboxLabel,
@@ -16,6 +16,35 @@ import './animation.css';
1616
export default component$(() => {
1717
const isListboxOpenSig = useSignal(false);
1818

19+
useStyles$(`
20+
@keyframes fadeIn {
21+
from {
22+
opacity: 0;
23+
}
24+
to {
25+
opacity: 1;
26+
}
27+
}
28+
29+
@keyframes fadeOut {
30+
from {
31+
opacity: 0;
32+
}
33+
to {
34+
opacity: 1;
35+
}
36+
}
37+
38+
.listbox-animation.popover-showing {
39+
animation: fadeIn both 500ms ease;
40+
}
41+
42+
.listbox-animation.popover-closing {
43+
animation: fadeOut both 500ms ease;
44+
}
45+
46+
`);
47+
1948
const animationExample = [
2049
'Red',
2150
'Orange',
@@ -58,7 +87,7 @@ export default component$(() => {
5887
</svg>
5988
</ComboboxTrigger>
6089
</ComboboxControl>
61-
<ComboboxPopover gutter={8}>
90+
<ComboboxPopover class="listbox-animation" gutter={8}>
6291
<ComboboxListbox
6392
class={`w-44 rounded-sm border-[1px] border-slate-400 bg-slate-900 px-4 py-2`}
6493
optionRenderer$={(option: ResolvedOption, index: number) => (

apps/website/src/routes/docs/headless/popover/index.mdx

Lines changed: 156 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,18 +201,21 @@ We can add a manual popover by adding the `popover="manual"` prop, or `manual` s
201201

202202
We can also enable programmatic behavior with popovers. Qwik UI provides several functions you can use to control this behavior.
203203

204-
<AnatomyTable
204+
<APITable
205205
propDescriptors={[
206206
{
207207
name: 'showPopover()',
208+
type: 'QRL',
208209
description: 'Opens the popover.',
209210
},
210211
{
211212
name: 'hidePopover()',
213+
type: 'QRL',
212214
description: 'Closes the popover.',
213215
},
214216
{
215217
name: 'togglePopover()',
218+
type: 'QRL',
216219
description: 'Toggles the popover between the open and closed state.',
217220
},
218221
]}
@@ -344,6 +347,7 @@ To do that, we can add the `listbox` class to the popover component.
344347
If you need to override any of the listbox properties, use the following CSS variables:
345348

346349
<AnatomyTable
350+
firstColumnLabel="Property"
347351
propDescriptors={[
348352
{
349353
name: 'margin',
@@ -401,11 +405,11 @@ Here's the CSS imported from the example:
401405
}
402406
}
403407

404-
.animate-in {
408+
.popover-showing {
405409
animation: fadeIn both 500ms ease;
406410
}
407411

408-
.animate-out {
412+
.popover-closing {
409413
animation: fadeOut both 500ms ease;
410414
}
411415
```
@@ -414,7 +418,7 @@ Here's the CSS imported from the example:
414418
415419
### Transition declarations
416420

417-
Transitions use the same classes for entry and exit animations. Those being `.popover-showing` and `.popover-closing`. They are explained move in the section above.
421+
Transitions use the same classes for entry and exit animations. Those being `.popover-showing` and `.popover-closing`. They are explained more in the `Caveats` section.
418422

419423
> The [View Transitions API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API) is another native solution that aims to solve animating between states. Support is currently in around **~70%** of browsers.
420424
@@ -430,7 +434,22 @@ To read more about the popover API you can check it out on:
430434

431435
## Backdrops
432436

433-
<Showcase name="backdrop" />
437+
Supported browsers provide a `::backdrop` pseudo element. For those looking to add a backdrop, the modal component might be a better option, as it provides more browser support for backdrops.
438+
439+
A backdrop across all browsers in the popover is possible too, but it requires a bit of extra work on the consumer side.
440+
441+
```tsx
442+
/* I style this as if it is the backdrop */
443+
<Popover id="my-backdrop">
444+
<div class="wrap">
445+
<div class="content">
446+
<Slot />
447+
</div>
448+
</div>
449+
</Popover>
450+
```
451+
452+
That said, if browser support is not a priority, feel free to use the native `::backdrop`. They are still supported in every major browser.
434453

435454
## Additional Examples
436455

@@ -445,3 +464,135 @@ Automatically places the listbox based on available space. **You must set flip t
445464
placement but with different strategies. Using both can result in a continuous reset
446465
loop as they try to override each other's work.
447466
</Note>
467+
468+
### Popover
469+
470+
<APITable
471+
propDescriptors={[
472+
{
473+
name: 'id',
474+
type: 'string',
475+
description: `Popover's id. Should match the popover target.`,
476+
},
477+
{
478+
name: 'popover',
479+
type: 'union',
480+
description:
481+
'Defines the popover behavior, can be auto or manual. Default is auto.',
482+
},
483+
{
484+
name: 'manual',
485+
type: 'boolean',
486+
description:
487+
'A manual popover needs to be manually hidden, such as toggling the button or programmatically.',
488+
},
489+
{
490+
name: 'floating',
491+
type: 'boolean',
492+
description: 'Enables extra JavaScript behavior for floating elements.',
493+
},
494+
{
495+
name: 'anchorRef',
496+
type: 'Signal',
497+
description: 'Signal reference that can be passed for floating behavior.',
498+
},
499+
{
500+
name: 'flip',
501+
type: 'boolean',
502+
description:
503+
'Flips the placement of the popover when it starts to collide with the boundaries.',
504+
},
505+
{
506+
name: 'gutter',
507+
type: 'number',
508+
description: 'The space between the floating element and the anchored element.',
509+
},
510+
{
511+
name: 'placement',
512+
type: 'union',
513+
info: ` | 'top'
514+
| 'top-start'
515+
| 'top-end'
516+
| 'right'
517+
| 'right-start'
518+
| 'right-end'
519+
| 'bottom'
520+
| 'bottom-start'
521+
| 'bottom-end'
522+
| 'left'
523+
| 'left-start'
524+
| 'left-end';`,
525+
description:
526+
'Flips the placement of the popover when it starts to collide with the boundaries.',
527+
},
528+
{
529+
name: 'autoPlacement',
530+
type: 'boolean',
531+
description: 'Automatically places the listbox based on available space.',
532+
},
533+
{
534+
name: '[popover]',
535+
type: 'selector',
536+
description: 'Selects the popover on all browsers.',
537+
},
538+
{
539+
name: ':popover-open',
540+
type: 'selector',
541+
description: 'Native supported pseudo element when the popover is open.',
542+
},
543+
{
544+
name: '.popover-open',
545+
type: 'class',
546+
description: 'Polyfill class added to style unsupported browsers.',
547+
},
548+
{
549+
name: '.popover-showing',
550+
type: 'class',
551+
description: 'Class to animate entry behavior.',
552+
},
553+
{
554+
name: '.popover-closing',
555+
type: 'class',
556+
description: 'Class to animate close behavior.',
557+
},
558+
{
559+
name: 'listbox',
560+
type: 'class',
561+
description: 'Class to add to the popover component for listbox behavior.',
562+
},
563+
]}
564+
/>
565+
566+
### Popover Trigger
567+
568+
<APITable
569+
propDescriptors={[
570+
{
571+
name: 'popovertarget',
572+
type: 'union',
573+
description: 'Accepts a string that matches the id of the popover.',
574+
},
575+
]}
576+
/>
577+
578+
### usePopover hook
579+
580+
<APITable
581+
propDescriptors={[
582+
{
583+
name: 'showPopover()',
584+
type: 'QRL',
585+
description: 'Opens the popover.',
586+
},
587+
{
588+
name: 'hidePopover()',
589+
type: 'QRL',
590+
description: 'Closes the popover.',
591+
},
592+
{
593+
name: 'togglePopover()',
594+
type: 'QRL',
595+
description: 'Toggles the popover between the open and closed state.',
596+
},
597+
]}
598+
/>

packages/kit-headless/src/components/popover/popover-impl.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,9 @@ export const PopoverImpl = component$<PopoverImplProps>((props) => {
9999

100100
console.log(e.newState);
101101

102-
setTimeout(() => {
103-
if (e.newState === 'open' && popoverRef.value) {
104-
supportShowAnimation(popoverRef.value);
105-
}
106-
}, 5);
102+
if (e.newState === 'open' && popoverRef.value) {
103+
supportShowAnimation(popoverRef.value, isPolyfillSig.value);
104+
}
107105

108106
if (e.newState === 'closed') {
109107
supportClosingAnimation(popoverRef.value);

packages/kit-headless/src/components/popover/utils.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,25 @@
11
/**
22
* Adds CSS-Class to support popover-opening-animation
33
*/
4-
export function supportShowAnimation(popover: HTMLElement) {
5-
popover.classList.remove('popover-closing');
6-
popover.classList.add('popover-showing');
4+
export function supportShowAnimation(popover: HTMLElement, isPolyfill: boolean) {
5+
const { transitionDuration } = getComputedStyle(popover);
6+
7+
if (isPolyfill) {
8+
// polyfill needs a bit of extra time to execute
9+
if (transitionDuration !== '0s') {
10+
setTimeout(() => {
11+
popover.classList.add('popover-showing');
12+
popover.classList.remove('popover-closing');
13+
}, 5);
14+
} else {
15+
console.log('running!');
16+
popover.classList.add('popover-showing');
17+
popover.classList.remove('popover-closing');
18+
}
19+
} else {
20+
popover.classList.add('popover-showing');
21+
popover.classList.remove('popover-closing');
22+
}
723
}
824

925
/**

0 commit comments

Comments
 (0)