Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: create tabs component #5964

Merged
merged 18 commits into from
Oct 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions COLLABORATOR_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ The Website also uses several other Open Source libraries (not limited to) liste
- [PostCSS Simple Vars](https://github.com/postcss/postcss-simple-vars)
- [Tailwind][] is used as our CSS Framework and the Foundation of our Design System
- [Hero Icons](https://heroicons.com/) is an SVG Icon Library used within our Codebase
- [Radix UI][] is a collection of customizable UI components
- [Shiki][] is a Syntax Highlighter used for our Codeboxes
- A [Rehype Plugin](https://rehype-pretty-code.netlify.app/) is used here for transforming `pre` and `code` tags into Syntax Highlighted Codeboxes
- [MDX][] and Markdown are used for structuring the Content of the Website
Expand Down Expand Up @@ -195,8 +196,8 @@ Finally, if you're unfamiliar with how to use Tailwind or how to use Tailwind wi
> You can apply Tailwind Tokens with Tailwind's `@apply` CSS rule. [Read more about applying Tailwind classes with `@apply`](https://tailwindcss.com/docs/functions-and-directives#apply).

> \[!IMPORTANT]\
> When using IDEs such as Visual Studio Code, we recommend installing the official [Stylelint](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)
> and [Tailwind](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint) Extensions.\
> When using IDEs such as Visual Studio Code, we recommend installing the official [Stylelint](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint)
> and [Tailwind](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) Extensions.\
> These are recommended Extensions for IntelliSense, Syntax Highlighting and Error Checking when styling your Component.

### Best practices when creating a Component
Expand Down Expand Up @@ -475,6 +476,12 @@ Defining a `.vscode` configuration like this also aides browser-only development

The npm ecosystem resolution and installation of `peerDependencies` installation [changed in recent versions](https://nodejs.org/en/blog/npm/peer-dependencies#using-peer-dependencies). The project documents what version of `Node.js` and `npm` to use via the [`.nvmrc` file](https://github.com/nodejs/nodejs.org/blob/main/.nvmrc). Not all contributors have tooling to automatically read this file and adhere to the correct version, however. To ensure all contributors install dependencies the same way, a local `.npmrc` file directly configures peerDependency installation behavior.

### Why we use RadixUI?

- It is a minimalistic component library broken down in individual packages for each Component
- It already handles all WAI-ARIA and Accessibility shortcuts/bindings needed for Interactive Elements
- It allows us to focus on designing interactive Components without the effort of adding all the surrounding sugar and code needed to make the Component accessibility-friendly.

## Seeking additional clarification

A lot of the current structure is due to retro-compatibility, keeping a simple and familiar file structure and keeping files that have historical reasons or needs.
Expand All @@ -491,3 +498,4 @@ If you're unfamiliar or curious about something, we recommend opening a Discussi
[React]: https://react.dev/
[Shiki]: https://github.com/shikijs/shiki
[Tailwind]: https://tailwindcss.com/
[Radix UI]: https://www.radix-ui.com/
53 changes: 53 additions & 0 deletions components/Common/Tabs/__tests__/index.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import * as TabsPrimitive from '@radix-ui/react-tabs';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import Tabs from '../index';

describe('Tabs', () => {
const tabs = [
{ key: 'package', label: 'Package Manager' },
{ key: 'prebuilt', label: 'Prebuilt Installer' },
{ key: 'source', label: 'Source Code' },
];

beforeEach(() => {
render(
<Tabs tabs={tabs} defaultValue="package">
<TabsPrimitive.Content value="package">
Package Manager
</TabsPrimitive.Content>
<TabsPrimitive.Content value="prebuilt">
Prebuilt Installer
</TabsPrimitive.Content>
<TabsPrimitive.Content value="source">
Source Code
</TabsPrimitive.Content>
</Tabs>
);
});

it('renders the correct number of tabs', () => {
const tabElements = screen.getAllByRole('tab');
expect(tabElements).toHaveLength(3);
});

it('renders the correct tab content when clicked', async () => {
const user = userEvent.setup();

const beforeActiveTabPanel = screen.getAllByRole('tabpanel');

expect(beforeActiveTabPanel).toHaveLength(1);

expect(beforeActiveTabPanel.at(0)).toHaveTextContent('Package Manager');

const tabElements = screen.getAllByRole('tab');
await user.click(tabElements.at(-1));

const afterActiveTabPanel = screen.getAllByRole('tabpanel');

expect(afterActiveTabPanel).toHaveLength(1);

expect(afterActiveTabPanel.at(0)).toHaveTextContent('Source Code');
});
});
20 changes: 20 additions & 0 deletions components/Common/Tabs/index.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.tabsList {
@apply flex
gap-1
font-open-sans;

.tabsTrigger {
@apply border-b-2
border-b-transparent
px-1
pb-[11px]
text-sm
font-semibold
text-neutral-800
data-[state=active]:border-b-green-600
data-[state=active]:text-green-600
dark:text-neutral-200
dark:data-[state=active]:border-b-green-400
dark:data-[state=active]:text-green-400;
}
}
42 changes: 42 additions & 0 deletions components/Common/Tabs/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import * as TabsPrimitive from '@radix-ui/react-tabs';
import type { Meta as MetaObj, StoryObj } from '@storybook/react';

import Tabs from './index';

type Story = StoryObj<typeof Tabs>;
type Meta = MetaObj<typeof Tabs>;

export const Default: Story = {
args: {
araujogui marked this conversation as resolved.
Show resolved Hide resolved
defaultValue: 'prebuilt',
tabs: [
{
key: 'package',
label: 'Package Manager',
},
{
key: 'prebuilt',
label: 'Prebuilt Installer',
},
{
key: 'source',
label: 'Source Code',
},
],
children: (
<>
<TabsPrimitive.Content value="package">
Package Manager
</TabsPrimitive.Content>
<TabsPrimitive.Content value="prebuilt">
Prebuilt Installer
</TabsPrimitive.Content>
<TabsPrimitive.Content value="source">
Source Code
</TabsPrimitive.Content>
</>
),
},
};

export default { component: Tabs } as Meta;
41 changes: 41 additions & 0 deletions components/Common/Tabs/index.tsx
ovflowd marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as TabsPrimitive from '@radix-ui/react-tabs';
import classNames from 'classnames';
import type { FC, PropsWithChildren } from 'react';

import styles from './index.module.css';

type Tab = {
key: string;
label: string;
};

type TabsProps = {
tabs: Tab[];
headerClassName?: string;
} & TabsPrimitive.TabsProps;

const Tabs: FC<PropsWithChildren<TabsProps>> = ({
tabs,
headerClassName,
children,
...props
}) => (
<TabsPrimitive.Root {...props}>
<TabsPrimitive.List
className={classNames(styles.tabsList, headerClassName)}
>
{tabs.map(tab => (
<TabsPrimitive.Trigger
key={tab.key}
value={tab.key}
className={styles.tabsTrigger}
>
{tab.label}
</TabsPrimitive.Trigger>
))}
</TabsPrimitive.List>
{children}
</TabsPrimitive.Root>
);

export default Tabs;
32 changes: 31 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@nodevu/core": "~0.1.0",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-toast": "^1.1.5",
"@radix-ui/react-tabs": "^1.0.4",
"@types/node": "18.18.3",
"@vcarl/remark-headings": "~0.1.0",
"@vercel/analytics": "^1.0.2",
Expand Down
1 change: 1 addition & 0 deletions tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export default {
900: '#411526',
},
white: '#FFFFFF',
transparent: 'transparent',
},
fontSize: {
xs: ['0.75rem', '1rem'],
Expand Down
Loading