Skip to content

Commit 6f1e462

Browse files
Tooltip Beta (#934)
* feat(tooltip): implement tooltip to beta phase * fix(tooltip): small tweaks to the tooltip state * fix: remove animations form tooltip docs and fix placement example * feat(tooltip): implement onOpenChange$ * chore: fix changeset type * test: update placement test to remove loop * fix: remove breaking examples and tooltip route * fix: checkbox tests preventing us from opening pw * refactor: deprecate popover hover prop in favor of tooltip * latest --------- Co-authored-by: Christopher Woolum <[email protected]>
1 parent e4bd153 commit 6f1e462

Some content is hidden

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

44 files changed

+1225
-152
lines changed

.changeset/tasty-pugs-decide.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@qwik-ui/headless': patch
3+
---
4+
5+
feat: implement a beta version of the Tooltip component

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,6 @@ export const statusByComponent: ComponentKitsStatuses = {
4949
Select: ComponentStatus.Beta,
5050
Separator: ComponentStatus.Beta,
5151
Tabs: ComponentStatus.Beta,
52-
Tooltip: ComponentStatus.Draft,
52+
Tooltip: ComponentStatus.Beta,
5353
},
5454
};

apps/website/src/components/showcase/showcase.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@ export const Showcase = component$<ShowcaseProps>(({ name, ...props }) => {
1818
const componentCodeSig = useSignal<string>();
1919

2020
useTask$(async () => {
21-
// eslint-disable-next-line qwik/valid-lexical-scope
22-
MetaGlobComponentSig.value = await metaGlobComponents[componentPath](); // We need to call `await metaGlobComponents[componentPath]()` in development as it is `eager:false`
23-
componentCodeSig.value = await rawComponents[componentPath]();
21+
try {
22+
// eslint-disable-next-line qwik/valid-lexical-scope
23+
MetaGlobComponentSig.value = await metaGlobComponents[componentPath](); // We need to call `await metaGlobComponents[componentPath]()` in development as it is `eager:false`
24+
componentCodeSig.value = await rawComponents[componentPath]();
25+
} catch (e) {
26+
throw new Error(`Unable to load path ${componentPath}`);
27+
}
2428
});
2529

2630
return (

apps/website/src/routes/docs/headless/popover/examples/corners.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { Popover } from '@qwik-ui/headless';
33

44
export default component$(() => {
55
return (
6-
<Popover.Root hover gutter={4} floating="top-end">
6+
<Popover.Root gutter={4} floating="top-end">
77
<div class="popover-container">
8-
<Popover.Trigger class="popover-trigger">Hover over me</Popover.Trigger>
8+
<Popover.Trigger class="popover-trigger">Click me</Popover.Trigger>
99
</div>
1010

1111
<Popover.Panel class="popover-panel">I am on the top-right corner!</Popover.Panel>

apps/website/src/routes/docs/headless/popover/examples/hover.tsx

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

apps/website/src/routes/docs/headless/popover/examples/placement.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import { Popover } from '@qwik-ui/headless';
33

44
export default component$(() => {
55
return (
6-
<Popover.Root hover gutter={4} floating="right">
6+
<Popover.Root gutter={4} floating="right">
77
<div class="popover-container">
88
<p>popover on the right ⤵️</p>
9-
<Popover.Trigger class="popover-trigger">Hover over me</Popover.Trigger>
9+
<Popover.Trigger class="popover-trigger">Click me</Popover.Trigger>
1010
</div>
1111

1212
<Popover.Panel class="popover-panel">I am anchored to the trigger!</Popover.Panel>

apps/website/src/routes/docs/headless/popover/examples/test-hide.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export default component$(() => {
44
const { hidePopover } = usePopover('hide-id');
55

66
return (
7-
<Popover.Root id="hide-id" manual hover>
7+
<Popover.Root id="hide-id" manual>
88
<button onClick$={() => hidePopover()}>hide popover</button>
99
<Popover.Trigger class="popover-trigger">Click me</Popover.Trigger>
1010
<Popover.Panel class="popover">My Hero!</Popover.Panel>

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ title: Qwik UI | Popover
33
---
44

55
import { statusByComponent } from '~/_state/component-statuses';
6+
67
import styles from './snippets/popover.css';
78

89
<StatusBanner status={statusByComponent.headless.Popover} />
@@ -273,12 +274,6 @@ Instead, the popover will be fixed position, and you can use CSS to position it.
273274

274275
The `Popover.Root` component is designed for positioning elements that float and facilitating interactions with them.
275276

276-
### Hover
277-
278-
If we'd like to show the `Popover.Panel` on hover, we can use the `hover` prop.
279-
280-
<Showcase name="hover" />
281-
282277
### Custom Floating Position
283278

284279
By default, popovers will float below the trigger component.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { component$ } from '@builder.io/qwik';
2+
import { Tooltip } from '@qwik-ui/headless';
3+
4+
import '../snippets/animation.css';
5+
6+
export default component$(() => {
7+
return (
8+
<Tooltip.Root gutter={4} flip>
9+
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
10+
<Tooltip.Panel class="tooltip-animation">
11+
Animated tooltip content here
12+
</Tooltip.Panel>
13+
</Tooltip.Root>
14+
);
15+
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { component$ } from '@builder.io/qwik';
2+
import { Tooltip } from '@qwik-ui/headless';
3+
4+
import '../snippets/arrow-styling.css';
5+
6+
export default component$(() => {
7+
return (
8+
<Tooltip.Root gutter={4} flip>
9+
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
10+
<Tooltip.Panel aria-label="Tooltip content" class="tooltip-arrow-styled-panel">
11+
<Tooltip.Arrow class="tooltip-arrow-styled-arrow" width={20} height={10} />
12+
<div>
13+
<h3 style="margin: 0 0 10px;">Tooltip Title</h3>
14+
<p style="margin: 0;">This tooltip has a snazzy styled arrow!</p>
15+
</div>
16+
</Tooltip.Panel>
17+
</Tooltip.Root>
18+
);
19+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { component$ } from '@builder.io/qwik';
2+
import { Tooltip } from '@qwik-ui/headless';
3+
4+
export default component$(() => {
5+
return (
6+
<Tooltip.Root gutter={4} flip>
7+
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
8+
<Tooltip.Panel class="tooltip-panel">Tooltip content here</Tooltip.Panel>
9+
</Tooltip.Root>
10+
);
11+
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { component$ } from '@builder.io/qwik';
2+
import { Tooltip } from '@qwik-ui/headless';
3+
4+
export default component$(() => {
5+
return (
6+
<Tooltip.Root gutter={4} flip>
7+
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
8+
<Tooltip.Panel aria-label="Tooltip content">
9+
<Tooltip.Arrow width={10} height={5} />
10+
Tooltip content here
11+
</Tooltip.Panel>
12+
</Tooltip.Root>
13+
);
14+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { component$ } from '@builder.io/qwik';
2+
import { Tooltip } from '@qwik-ui/headless';
3+
4+
export default component$(() => {
5+
return (
6+
<Tooltip.Root gutter={4} flip placement="bottom">
7+
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
8+
<Tooltip.Panel aria-label="Complex Tooltip content">
9+
<Tooltip.Arrow width={10} height={5} />
10+
<div>
11+
<h3>Tooltip Title</h3>
12+
<p>This is a tooltip with complex HTML content, including:</p>
13+
<ul>
14+
<li>List item 1</li>
15+
<li>List item 2</li>
16+
<li>List item 3</li>
17+
</ul>
18+
</div>
19+
</Tooltip.Panel>
20+
</Tooltip.Root>
21+
);
22+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { component$ } from '@builder.io/qwik';
2+
import { Tooltip } from '@qwik-ui/headless';
3+
4+
export default component$(() => {
5+
return (
6+
<Tooltip.Root gutter={4} flip>
7+
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
8+
<Tooltip.Panel class="tooltip-panel">
9+
Tooltip content with flip enabled
10+
</Tooltip.Panel>
11+
</Tooltip.Root>
12+
);
13+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { component$ } from '@builder.io/qwik';
2+
import { Tooltip } from '@qwik-ui/headless';
3+
4+
export default component$(() => {
5+
return (
6+
<Tooltip.Root gutter={4} flip>
7+
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
8+
<Tooltip.Panel class="tooltip-panel">Floating Tooltip content here</Tooltip.Panel>
9+
</Tooltip.Root>
10+
);
11+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { component$ } from '@builder.io/qwik';
2+
import { Tooltip } from '@qwik-ui/headless';
3+
4+
export default component$(() => {
5+
return (
6+
<Tooltip.Root gutter={20} flip>
7+
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
8+
<Tooltip.Panel class="tooltip-panel">Tooltip content with gutter</Tooltip.Panel>
9+
</Tooltip.Root>
10+
);
11+
});
Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
1-
import { component$, useStyles$ } from '@builder.io/qwik';
1+
import { component$ } from '@builder.io/qwik';
22
import { Tooltip } from '@qwik-ui/headless';
33

44
export default component$(() => {
5-
useStyles$(styles);
6-
75
return (
8-
<Tooltip.Root>
9-
<Tooltip.Trigger class="tooltip-trigger">Hover over me</Tooltip.Trigger>
10-
<Tooltip.Content class="tooltip-content">I'm a tooltip!</Tooltip.Content>
6+
<Tooltip.Root gutter={4} flip>
7+
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
8+
<Tooltip.Panel class="tooltip-panel">Tooltip content here</Tooltip.Panel>
119
</Tooltip.Root>
1210
);
1311
});
14-
15-
// internal
16-
import styles from '../snippets/tooltip.css?inline';
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { component$, useSignal } from '@builder.io/qwik';
2+
import { Tooltip } from '@qwik-ui/headless';
3+
4+
export default component$(() => {
5+
const tooltipState = useSignal<'open' | 'closed'>('closed');
6+
7+
return (
8+
<>
9+
<Tooltip.Root gutter={4} onOpenChange$={(e) => (tooltipState.value = e)} flip>
10+
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
11+
<Tooltip.Panel aria-label="Tooltip content">
12+
<Tooltip.Arrow width={10} height={5} />
13+
Tooltip content here
14+
</Tooltip.Panel>
15+
</Tooltip.Root>
16+
The tooltip is {tooltipState.value}
17+
</>
18+
);
19+
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { component$, useSignal } from '@builder.io/qwik';
2+
import { Tooltip } from '@qwik-ui/headless';
3+
4+
export default component$(() => {
5+
const placement = useSignal<'top' | 'right' | 'bottom' | 'left'>('top');
6+
7+
return (
8+
<div>
9+
<label for="placement">Select Tooltip Placement: </label>
10+
<select
11+
id="placement"
12+
value={placement.value}
13+
onChange$={(e) =>
14+
(placement.value = (e.target as HTMLSelectElement).value as
15+
| 'top'
16+
| 'right'
17+
| 'bottom'
18+
| 'left')
19+
}
20+
>
21+
<option value="top">Top</option>
22+
<option value="right">Right</option>
23+
<option value="bottom">Bottom</option>
24+
<option value="left">Left</option>
25+
</select>
26+
27+
<Tooltip.Root key={placement.value} gutter={4} flip placement={placement.value}>
28+
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
29+
<Tooltip.Panel
30+
aria-label={`Tooltip content on the ${placement.value}`}
31+
class="tooltip-panel"
32+
>
33+
Tooltip content on the {placement.value}
34+
</Tooltip.Panel>
35+
</Tooltip.Root>
36+
</div>
37+
);
38+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { component$ } from '@builder.io/qwik';
2+
import { Tooltip } from '@qwik-ui/headless';
3+
import '../snippets/styling.css';
4+
5+
export default component$(() => {
6+
return (
7+
<Tooltip.Root delayDuration={800} gutter={4} flip>
8+
<Tooltip.Trigger class="custom-trigger">Hover or Focus me</Tooltip.Trigger>
9+
<Tooltip.Panel class="custom-tooltip-panel">Tooltip content here</Tooltip.Panel>
10+
</Tooltip.Root>
11+
);
12+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { component$ } from '@builder.io/qwik';
2+
import { Tooltip } from '@qwik-ui/headless';
3+
4+
import '../snippets/transition.css';
5+
6+
export default component$(() => {
7+
return (
8+
<Tooltip.Root gutter={4} flip>
9+
<Tooltip.Trigger>Hover or Focus me</Tooltip.Trigger>
10+
<Tooltip.Panel class="tooltip-transition">
11+
Tooltip content with transition
12+
</Tooltip.Panel>
13+
</Tooltip.Root>
14+
);
15+
});

0 commit comments

Comments
 (0)