Skip to content

Commit e8209aa

Browse files
authored
feat(styled kit): tooltip component (#1094)
* chore: wip * feat(styled kit): tooltip component
1 parent 0124d0c commit e8209aa

File tree

11 files changed

+154
-12
lines changed

11 files changed

+154
-12
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const statusByComponent: ComponentKitsStatuses = {
1515
Dropdown: ComponentStatus.Draft,
1616
RadioGroup: ComponentStatus.Draft,
1717
Carousel: ComponentStatus.Draft,
18+
Tooltip: ComponentStatus.Draft,
1819
},
1920
headless: {
2021
Checkbox: ComponentStatus.Draft,
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export const api = {
2+
"tooltip": [
3+
{
4+
"tooltip-arrow": []
5+
},
6+
{
7+
"tooltip-panel": []
8+
},
9+
{
10+
"tooltip-root": []
11+
},
12+
{
13+
"tooltip-trigger": []
14+
}
15+
]
16+
};

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ A text label that appears when a user hovers, focuses, or touches an element.
2121
`Opens on hover or focus`,
2222
'Closes on trigger activation or Escape key press',
2323
'Customizable open/close delays',
24-
'Optional arrow component',
24+
{/* 'Optional arrow component', */}
2525
'Always portaled content',
2626
'Accessibility with ARIA roles and keyboard interactions',
2727
'Flipping to avoid overflow',
@@ -44,7 +44,6 @@ export default component$(() => {
4444
<button>Hover or Focus me</button>
4545
</Tooltip.Trigger>
4646
<Tooltip.Panel aria-label="Tooltip content">
47-
<Tooltip.Arrow width={10} height={5} />
4847
Tooltip content here
4948
</Tooltip.Panel>
5049
</Tooltip.Root>
@@ -68,10 +67,10 @@ export default component$(() => {
6867
name: 'Tooltip.Panel',
6968
description: `An HTML element that contains the tooltip content.`,
7069
},
71-
{
70+
{/* {
7271
name: 'Tooltip.Arrow',
7372
description: `An optional arrow component to point to the trigger element.`,
74-
},
73+
}, */}
7574
]}
7675
/>
7776

@@ -276,10 +275,10 @@ To read more about tooltips you can check it out on:
276275
name: 'Tooltip.Panel',
277276
description: 'The container for the tooltip content.',
278277
},
279-
{
278+
{/* {
280279
name: 'Tooltip.Arrow',
281280
description: 'An optional arrow component for the tooltip.',
282-
},
281+
}, */}
283282
]}
284283
/>
285284

apps/website/src/routes/docs/styled/menu.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,4 @@
3939
- [Textarea](/docs/styled/textarea)
4040
- [Toggle](/docs/styled/toggle)
4141
- [ToggleGroup](/docs/styled/toggle-group)
42+
- [Tooltip](/docs/styled/tooltip)

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import { statusByComponent } from '~/_state/component-statuses';
66

77
import { ShowcaseHero } from './showcase-components';
88

9-
<StatusBanner status={statusByComponent.styled.Popover} />
10-
119
# Popover
1210

1311
A non-modal primitive with overlays that open and close around a DOM element.
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, badgeVariants } from '~/components/ui';
3+
4+
export default component$(() => {
5+
return (
6+
<Tooltip.Root flip={false} gutter={8}>
7+
<Tooltip.Trigger class={badgeVariants({ look: 'outline' })}>
8+
Hover over me.
9+
</Tooltip.Trigger>
10+
<Tooltip.Panel>
11+
<p>Add to library</p>
12+
</Tooltip.Panel>
13+
</Tooltip.Root>
14+
);
15+
});

apps/website/src/routes/docs/styled/tooltip/index.mdx

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,72 @@ title: Qwik UI | Styled Tooltip Component
44

55
import { statusByComponent } from '~/_state/component-statuses';
66

7+
import { ShowcaseHero } from './showcase-components';
8+
9+
<StatusBanner status={statusByComponent.styled.Tooltip} />
10+
711
# Tooltip
812

9-
Don't be a fool, use a Qwik UI Styled tooltip. or how we call it internally.. a fooltip! (WAT?)
13+
A text label that appears when a user hovers, focuses, or touches an element.
1014

11-
<StatusBanner status={statusByComponent.styled.Tooltip} />
15+
<ShowcaseHero />
16+
17+
## Installation
18+
19+
### Run the following cli command or copy/paste the component code into your project
20+
21+
```sh
22+
qwik-ui add tooltip
23+
```
24+
25+
```tsx
26+
import { type PropsOf, Slot, component$ } from '@builder.io/qwik';
27+
import { Tooltip as HeadlessTooltip } from '@qwik-ui/headless';
28+
import { cn } from '@qwik-ui/utils';
29+
30+
const Root = component$<PropsOf<typeof HeadlessTooltip.Root>>(({ ...props }) => {
31+
return (
32+
<HeadlessTooltip.Root {...props}>
33+
<Slot />
34+
</HeadlessTooltip.Root>
35+
);
36+
});
37+
38+
const Trigger = HeadlessTooltip.Trigger;
39+
40+
const Panel = component$<PropsOf<typeof HeadlessTooltip.Panel>>(({ ...props }) => {
41+
return (
42+
<HeadlessTooltip.Panel
43+
{...props}
44+
class={cn(
45+
'w-fit text-balance rounded-md border bg-background px-3 py-1.5 text-xs text-foreground shadow animate-in fade-in-0 zoom-in-95',
46+
'data-[closed]:animate-out data-[closed]:fade-out-0 data-[closed]:zoom-out-95',
47+
'data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
48+
props.class,
49+
)}
50+
>
51+
<Slot />
52+
</HeadlessTooltip.Panel>
53+
);
54+
});
55+
56+
export const Tooltip = {
57+
Root,
58+
Trigger,
59+
Panel,
60+
};
61+
62+
```
63+
64+
## Usage
65+
66+
```tsx
67+
import { Tooltip } from '~/components/ui';
68+
```
69+
70+
```tsx
71+
<Tooltip.Root>
72+
<Tooltip.Trigger>Open Trigger</Tooltip.Trigger>
73+
<Tooltip.Panel>Place your content here.</Tooltip.Panel>
74+
</Tooltip.Root>
75+
```
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 { Showcase } from '~/components/showcase/showcase';
3+
4+
import Hero from './examples/hero';
5+
import HeroRawCode from './examples/hero.tsx?raw';
6+
export const ShowcaseHero = component$(() => {
7+
return (
8+
<Showcase rawCode={HeroRawCode}>
9+
<Hero />
10+
</Showcase>
11+
);
12+
});

packages/kit-headless/src/components/tooltip/tooltip-arrow.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ export type TooltipArrowProps = {
2424
* HTooltipArrow is the arrow component for the Tooltip.
2525
*/
2626
export const HTooltipArrow = component$((props: TooltipArrowProps) => {
27-
const { width = 10, height = 5, class: className } = props;
27+
const { width = 10, height = 5 } = props;
2828

2929
return (
3030
<div
31-
class={`tooltip-arrow ${className}`}
31+
class={['tooltip-arrow', props.class]}
3232
style={{
3333
width: `${width}px`,
3434
height: `${height}px`,
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { type PropsOf, Slot, component$ } from '@builder.io/qwik';
2+
import { Tooltip as HeadlessTooltip } from '@qwik-ui/headless';
3+
import { cn } from '@qwik-ui/utils';
4+
5+
const Root = component$<PropsOf<typeof HeadlessTooltip.Root>>(({ ...props }) => {
6+
return (
7+
<HeadlessTooltip.Root {...props}>
8+
<Slot />
9+
</HeadlessTooltip.Root>
10+
);
11+
});
12+
13+
const Trigger = HeadlessTooltip.Trigger;
14+
15+
const Panel = component$<PropsOf<typeof HeadlessTooltip.Panel>>(({ ...props }) => {
16+
return (
17+
<HeadlessTooltip.Panel
18+
{...props}
19+
class={cn(
20+
'w-fit text-balance rounded-md border bg-background px-3 py-1.5 text-xs text-foreground shadow animate-in fade-in-0 zoom-in-95',
21+
'data-[closed]:animate-out data-[closed]:fade-out-0 data-[closed]:zoom-out-95',
22+
'data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
23+
props.class,
24+
)}
25+
>
26+
<Slot />
27+
</HeadlessTooltip.Panel>
28+
);
29+
});
30+
31+
export const Tooltip = {
32+
Root,
33+
Trigger,
34+
Panel,
35+
};

0 commit comments

Comments
 (0)