Skip to content

Commit

Permalink
feat(tooltip): add radix-ui tooltip component (#39)
Browse files Browse the repository at this point in the history
* feat(tooltip): add radix-ui tooltip component

* feat(tooltip): fix export
  • Loading branch information
mgray-sonalake authored Feb 18, 2022
1 parent 6e8b2f3 commit f9d337b
Show file tree
Hide file tree
Showing 13 changed files with 270 additions and 31 deletions.
4 changes: 3 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
module.exports = {
setupFilesAfterEnv: ['./src/setupTests.ts'],
clearMocks: true,
moduleNameMapper: {
'\\.(css|sass|scss)$': 'identity-obj-proxy',
'\\.svg$': 'jest-transform-stub',
},
setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts'],
testEnvironment: 'jsdom',
};
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
},
"peerDependencies": {
"@radix-ui/react-alert-dialog": "^0.1.5",
"@radix-ui/react-tooltip": "^0.1.6",
"clsx": "^1.1.1",
"react": ">=16",
"react-icons": "^4.3.1"
"react": ">=16"
},
"husky": {
"hooks": {
Expand Down Expand Up @@ -68,6 +68,7 @@
"@commitlint/cli": "^16.1.0",
"@commitlint/config-conventional": "^16.0.0",
"@radix-ui/react-alert-dialog": "^0.1.5",
"@radix-ui/react-tooltip": "^0.1.6",
"@size-limit/preset-small-lib": "^7.0.8",
"@storybook/addon-essentials": "^6.4.18",
"@storybook/addon-info": "^5.3.21",
Expand Down
12 changes: 12 additions & 0 deletions src/__mocks__/DOMRect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class DOMRect {
static fromRect() {
return {
height: 0,
width: 0,
x: 0,
y: 0,
};
}
}

global.DOMRect = DOMRect;
6 changes: 6 additions & 0 deletions src/__mocks__/ResizeObserver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class ResizeObserver {
observe() {}
unobserve() {}
}

global.ResizeObserver = ResizeObserver;
1 change: 1 addition & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import './style.css';

export * from './models';
export * from './ui';
6 changes: 6 additions & 0 deletions src/setupTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,11 @@ import { toHaveNoViolations } from 'jest-axe';

import '@testing-library/jest-dom';
import 'regenerator-runtime/runtime.js';
import './__mocks__/DOMRect';
import './__mocks__/ResizeObserver';
/**
* Need to mock above as not included in jest/jsdom
* see https://github.com/radix-ui/primitives/issues/420#issuecomment-771615182
*/

expect.extend(toHaveNoViolations);
56 changes: 29 additions & 27 deletions src/ui/alert/alert.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,35 @@ import {
AlertTrigger,
} from './components';

test('renders an accessible alert dialog', async () => {
const { container } = render(
<Alert>
<AlertTrigger asChild>
<button>Trigger</button>
</AlertTrigger>
<AlertContent>
<AlertTitle>Title</AlertTitle>
<AlertDescription>Description</AlertDescription>
<AlertCancel asChild>
<button>Cancel</button>
</AlertCancel>
<AlertAction asChild>
<button>Action</button>
</AlertAction>
</AlertContent>
</Alert>
);
describe('Alert', () => {
test('renders an accessible alert dialog', async () => {
const { container } = render(
<Alert>
<AlertTrigger asChild>
<button>Trigger</button>
</AlertTrigger>
<AlertContent>
<AlertTitle>Title</AlertTitle>
<AlertDescription>Description</AlertDescription>
<AlertCancel asChild>
<button>Cancel</button>
</AlertCancel>
<AlertAction asChild>
<button>Action</button>
</AlertAction>
</AlertContent>
</Alert>
);

userEvent.click(screen.getByRole('button', { name: 'Trigger' }));
userEvent.click(screen.getByRole('button', { name: 'Trigger' }));

expect(
screen.getByRole('alertdialog', { name: 'Title' })
).toBeInTheDocument();
expect(screen.getByRole('alertdialog')).toHaveAccessibleDescription(
'Description'
);
expect(screen.getByRole('button', { name: 'Cancel' })).toHaveFocus();
expect(await axe(container)).toHaveNoViolations();
expect(
screen.getByRole('alertdialog', { name: 'Title' })
).toBeInTheDocument();
expect(screen.getByRole('alertdialog')).toHaveAccessibleDescription(
'Description'
);
expect(screen.getByRole('button', { name: 'Cancel' })).toHaveFocus();
expect(await axe(container)).toHaveNoViolations();
});
});
2 changes: 2 additions & 0 deletions src/ui/tooltip/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './tooltip.component';
export * from './tooltip.context';
50 changes: 50 additions & 0 deletions src/ui/tooltip/tooltip.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React, { ReactNode } from 'react';
import {
Arrow,
Content,
Root,
TooltipContentProps,
TooltipProps,
Trigger,
} from '@radix-ui/react-tooltip';
import clsx from 'clsx';

export type TooltipOwnProps = {
children: ReactNode;
content: ReactNode;
side?: TooltipContentProps['side'];
padding?: 'sm' | 'md';
defaultOpen?: boolean;
open?: boolean;
onOpenChange?: TooltipProps['onOpenChange'];
};

export const Tooltip = ({
children,
content,
side = 'top',
padding = 'sm',
open,
defaultOpen,
onOpenChange,
}: TooltipOwnProps) => (
<Root
open={open}
defaultOpen={defaultOpen}
delayDuration={300}
onOpenChange={onOpenChange}
>
<Trigger asChild>{children}</Trigger>
<Content side={side} sideOffset={6} align="center" asChild>
<div
className={clsx('max-w-xs rounded bg-white shadow-lg text-sm', {
'p-2': padding === 'sm',
'p-4': padding === 'md',
})}
>
{content}
<Arrow className="fill-current text-white" width={14} height={8} />
</div>
</Content>
</Root>
);
3 changes: 3 additions & 0 deletions src/ui/tooltip/tooltip.context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Provider } from '@radix-ui/react-tooltip';

export const TooltipProvider = Provider;
22 changes: 22 additions & 0 deletions src/ui/tooltip/tooltip.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { axe } from 'jest-axe';

import { Tooltip } from './tooltip.component';
import { TooltipProvider } from './tooltip.context';

describe('Tooltip', () => {
test('has no accessibility violations', async () => {
const { container } = render(
<TooltipProvider>
<Tooltip content="Tooltip Content" defaultOpen>
<button type="button">Trigger</button>
</Tooltip>
</TooltipProvider>
);

expect(screen.getByRole('button', { name: 'Trigger' })).toBeInTheDocument();

expect(await axe(container)).toHaveNoViolations();
});
});
43 changes: 43 additions & 0 deletions src/ui/tooltip/tooltip.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';
import { ComponentMeta, ComponentStory } from '@storybook/react';

import { Tooltip } from './tooltip.component';
import { TooltipProvider } from './tooltip.context';

const meta: ComponentMeta<typeof Tooltip> = {
title: 'Atoms/Tooltip',
component: Tooltip,
parameters: {
backgrounds: {
default: 'light',
},
},
decorators: [
(Story) => (
<div className="m-32">
<TooltipProvider>
<Story />
</TooltipProvider>
</div>
),
],
};

export default meta;

const Template: ComponentStory<typeof Tooltip> = (args) => (
<Tooltip {...args} />
);

export const Default = Template.bind({});
Default.args = {
children: <button>Show Tooltip</button>,
content: 'This is the content!',
side: 'bottom',
};

export const OpenByDefault = Template.bind({});
OpenByDefault.args = {
...Default.args,
defaultOpen: true,
};
91 changes: 90 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2041,6 +2041,14 @@
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.2.tgz#830beaec4b4091a9e9398ac50f865ddea52186b9"
integrity sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==

"@radix-ui/popper@0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/popper/-/popper-0.1.0.tgz#c387a38f31b7799e1ea0d2bb1ca0c91c2931b063"
integrity sha512-uzYeElL3w7SeNMuQpXiFlBhTT+JyaNMCwDfjKkrzugEcYrf5n52PHqncNdQPUtR42hJh8V9FsqyEDbDxkeNjJQ==
dependencies:
"@babel/runtime" "^7.13.10"
csstype "^3.0.4"

"@radix-ui/primitive@0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-0.1.0.tgz#6206b97d379994f0d1929809db035733b337e543"
Expand All @@ -2061,6 +2069,14 @@
"@radix-ui/react-primitive" "0.1.3"
"@radix-ui/react-slot" "0.1.2"

"@radix-ui/react-arrow@0.1.3":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-0.1.3.tgz#17f86eab216c48aff17b13b811569a9bbabaa44d"
integrity sha512-9x1gRYdlUD5OUwY7L+M+4FY/YltDSsrNSj8QXGPbxZxL5ghWXB/4lhyIGccCwk/e8ggfmQYv9SRNmn3LavPo3A==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-primitive" "0.1.3"

"@radix-ui/react-compose-refs@0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-0.1.0.tgz#cff6e780a0f73778b976acff2c2a5b6551caab95"
Expand Down Expand Up @@ -2134,6 +2150,21 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-use-layout-effect" "0.1.0"

"@radix-ui/react-popper@0.1.3":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-0.1.3.tgz#a93bdd72845566007e5f3868caddd62318bb781e"
integrity sha512-2OV2YaJv7iTZexJY3HJ7B6Fs1A/3JXd3fRGU4JY0guACfGMD1C/jSgds505MKQOTiHE/quI6j3/q8yfzFjJR9g==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/popper" "0.1.0"
"@radix-ui/react-arrow" "0.1.3"
"@radix-ui/react-compose-refs" "0.1.0"
"@radix-ui/react-context" "0.1.1"
"@radix-ui/react-primitive" "0.1.3"
"@radix-ui/react-use-rect" "0.1.1"
"@radix-ui/react-use-size" "0.1.0"
"@radix-ui/rect" "0.1.1"

"@radix-ui/react-portal@0.1.3":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-0.1.3.tgz#56826e789b3d4e37983f6d23666e3f1b1b9ee358"
Expand Down Expand Up @@ -2168,6 +2199,27 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-compose-refs" "0.1.0"

"@radix-ui/react-tooltip@^0.1.6":
version "0.1.6"
resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-0.1.6.tgz#46a3e385e004aaebd16ecaa1da7d1af70ba3bb45"
integrity sha512-0uaRpRmTCQo5yMUkDpv4LEDnaQDoeLXcNNhZonCZdbZBQ7ntvjURIWIigq1/pXZp0UX7oPpFzsXD9jUp8JT0WA==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/primitive" "0.1.0"
"@radix-ui/react-compose-refs" "0.1.0"
"@radix-ui/react-context" "0.1.1"
"@radix-ui/react-id" "0.1.4"
"@radix-ui/react-popper" "0.1.3"
"@radix-ui/react-portal" "0.1.3"
"@radix-ui/react-presence" "0.1.1"
"@radix-ui/react-primitive" "0.1.3"
"@radix-ui/react-slot" "0.1.2"
"@radix-ui/react-use-controllable-state" "0.1.0"
"@radix-ui/react-use-escape-keydown" "0.1.0"
"@radix-ui/react-use-previous" "0.1.0"
"@radix-ui/react-use-rect" "0.1.1"
"@radix-ui/react-visually-hidden" "0.1.3"

"@radix-ui/react-use-body-pointer-events@0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-body-pointer-events/-/react-use-body-pointer-events-0.1.0.tgz#29b211464493f8ca5149ce34b96b95abbc97d741"
Expand Down Expand Up @@ -2206,6 +2258,43 @@
dependencies:
"@babel/runtime" "^7.13.10"

"@radix-ui/react-use-previous@0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-0.1.0.tgz#fed880d41187d0fdd1e19c4588402765f342777e"
integrity sha512-0fxNc33rYnCzDMPSiSnfS8YklnxQo8WqbAQXPAgIaaA1jRu2qFB916PL4qCIW+avcAAqFD38vWhqDqcVmBharA==
dependencies:
"@babel/runtime" "^7.13.10"

"@radix-ui/react-use-rect@0.1.1":
version "0.1.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-0.1.1.tgz#6c15384beee59c086e75b89a7e66f3d2e583a856"
integrity sha512-kHNNXAsP3/PeszEmM/nxBBS9Jbo93sO+xuMTcRfwzXsmxT5gDXQzAiKbZQ0EecCPtJIzqvr7dlaQi/aP1PKYqQ==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/rect" "0.1.1"

"@radix-ui/react-use-size@0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-0.1.0.tgz#dc49295d646f5d3f570943dbb88bd94fc7db7daf"
integrity sha512-TcZAsR+BYI46w/RbaSFCRACl+Jh6mDqhu6GS2r0iuJpIVrj8atff7qtTjmMmfGtEDNEjhl7DxN3pr1nTS/oruQ==
dependencies:
"@babel/runtime" "^7.13.10"

"@radix-ui/react-visually-hidden@0.1.3":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-0.1.3.tgz#406a2f1e2f2cf27e5b85a29dc3aca718e695acaf"
integrity sha512-dPU6ZR2WQ/W9qv7E1Y8/I8ymqG+8sViU6dQQ6sfr2/8yGr0I4mmI7ywTnqXaE+YS9gHLEZHdQcEqTNESg6YfdQ==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-primitive" "0.1.3"

"@radix-ui/rect@0.1.1":
version "0.1.1"
resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-0.1.1.tgz#95b5ba51f469bea6b1b841e2d427e17e37d38419"
integrity sha512-g3hnE/UcOg7REdewduRPAK88EPuLZtaq7sA9ouu8S+YEtnyFRI16jgv6GZYe3VMoQLL1T171ebmEPtDjyxWLzw==
dependencies:
"@babel/runtime" "^7.13.10"

"@reach/router@^1.2.1":
version "1.3.4"
resolved "https://registry.yarnpkg.com/@reach/router/-/router-1.3.4.tgz#d2574b19370a70c80480ed91f3da840136d10f8c"
Expand Down Expand Up @@ -6333,7 +6422,7 @@ csstype@^2.5.7:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.19.tgz#feeb5aae89020bb389e1f63669a5ed490e391caa"
integrity sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==

csstype@^3.0.2:
csstype@^3.0.2, csstype@^3.0.4:
version "3.0.10"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5"
integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==
Expand Down

0 comments on commit f9d337b

Please sign in to comment.