1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-24 15:59:41 +02:00

refactor(app): move react components to react codebase [EE-3179] (#6971)

This commit is contained in:
Chaim Lev-Ari 2022-06-17 19:18:42 +03:00 committed by GitHub
parent 212400c283
commit 18252ab854
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
346 changed files with 642 additions and 644 deletions

View file

@ -0,0 +1,32 @@
.parent {
background: var(--blue-4);
border-radius: 4px 4px 0 0;
padding-top: 5px;
margin-top: -5px;
}
.parent a {
background-color: initial !important;
border: 1px solid transparent !important;
cursor: inherit !important;
}
.parent {
background-color: var(--blue-4);
}
:global(:root[theme='dark']) .parent {
background-color: var(--grey-40);
}
:global(:root[theme='highcontrast']) .parent {
background-color: var(--white-color);
}
.parent a {
color: var(--white-color) !important;
}
:global([theme='dark']) .parent a {
color: var(--black-color) !important;
}
:global([theme='highcontrast']) .parent a {
color: var(--black-color) !important;
}

View file

@ -0,0 +1,31 @@
import { ComponentMeta, Story } from '@storybook/react';
import { useState } from 'react';
import { NavTabs, type Option } from './NavTabs';
export default {
title: 'Components/NavTabs',
component: NavTabs,
} as ComponentMeta<typeof NavTabs>;
type Args = {
options: Option[];
};
function Template({ options = [] }: Args) {
const [selected, setSelected] = useState(
options.length ? options[0].id : undefined
);
return (
<NavTabs options={options} selectedId={selected} onSelect={setSelected} />
);
}
export const Example: Story<Args> = Template.bind({});
Example.args = {
options: [
{ children: 'Content 1', id: 'option1', label: 'Option 1' },
{ children: 'Content 2', id: 'option2', label: 'Option 2' },
],
};

View file

@ -0,0 +1,58 @@
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { NavTabs, Option } from './NavTabs';
test('should show titles', async () => {
const options = [
{ children: 'Content 1', id: 'option1', label: 'Option 1' },
{ children: 'Content 2', id: 'option2', label: 'Option 2' },
];
const { findByText } = renderComponent(options);
const heading = await findByText(options[0].label);
expect(heading).toBeTruthy();
const heading2 = await findByText(options[1].label);
expect(heading2).toBeTruthy();
});
test('should show selected id content', async () => {
const options = [
{ children: 'Content 1', id: 'option1', label: 'Option 1' },
{ children: 'Content 2', id: 'option2', label: 'Option 2' },
];
const selected = options[1];
const { findByText } = renderComponent(options, selected.id);
const content = await findByText(selected.children);
expect(content).toBeTruthy();
});
test('should call onSelect when clicked with id', async () => {
const options = [
{ children: 'Content 1', id: 'option1', label: 'Option 1' },
{ children: 'Content 2', id: 'option2', label: 'Option 2' },
];
const onSelect = jest.fn();
const { findByText } = renderComponent(options, options[1].id, onSelect);
const heading = await findByText(options[0].label);
userEvent.click(heading);
expect(onSelect).toHaveBeenCalledWith(options[0].id);
});
function renderComponent(
options: Option[] = [],
selectedId?: string | number,
onSelect?: (id: string | number) => void
) {
return render(
<NavTabs options={options} selectedId={selectedId} onSelect={onSelect} />
);
}

View file

@ -0,0 +1,60 @@
import clsx from 'clsx';
import { ReactNode } from 'react';
import styles from './NavTabs.module.css';
export interface Option {
label: string | ReactNode;
children?: ReactNode;
id: string | number;
}
interface Props {
options: Option[];
selectedId?: string | number;
onSelect?(id: string | number): void;
}
export function NavTabs({ options, selectedId, onSelect = () => {} }: Props) {
const selected = options.find((option) => option.id === selectedId);
return (
<>
<ul className="nav nav-tabs">
{options.map((option) => (
<li
className={clsx({
active: option.id === selectedId,
[styles.parent]: !option.children,
})}
key={option.id}
>
{/* rule disabled because `nav-tabs` requires an anchor */}
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
<a
onClick={() => handleSelect(option)}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
handleSelect(option);
}
}}
role="button"
tabIndex={0}
>
{option.label}
</a>
</li>
))}
</ul>
{selected && selected.children && (
<div className="tab-content">{selected.children}</div>
)}
</>
);
function handleSelect(option: Option) {
if (option.children) {
onSelect(option.id);
}
}
}

View file

@ -0,0 +1 @@
export { NavTabs } from './NavTabs';