Skip to content

Commit

Permalink
Adiciona componente de primeiro comentário (#192)
Browse files Browse the repository at this point in the history
* feat: add checkbox component

* feat: change FirstComment to Checkbox and add variants

* feat: changes in checkbox component

* feat: add accordion component

* test: add unit tests for checkbox component

* test: add tests for accordion component

* feat: add first comment component

* docs: add docs for new components checkbox, accordion and firstComment

* test: change get to find

* feat: change render to pass element directly

* refactor: remove barrels imports

* refactor: externalize accordion functionality

* feat: remove functionalities of checkbox

* feat: remove optional props in checkbox

* feat: update checkbox styles from px to rem

* feat: add checked type to checkbox

* test: update checkbox test

* feat: change all px to rem

* refactor: remove accordion destructuring

* feat: update checkbox styles

* refactor: remove accordion spread

* style: stylelint

* tests: use nested describes instead it message

* refactor: remove unused padding in checkbox

* refactor: checkbox stories

* style: just stylelint

---------

Co-authored-by: Andre Almeida <andre-silva78@hotmail.com>
  • Loading branch information
alvarogfn and aalmeida00 authored Nov 21, 2023
1 parent 6d8f398 commit 07c6f2a
Show file tree
Hide file tree
Showing 19 changed files with 432 additions and 46 deletions.
11 changes: 11 additions & 0 deletions src/components/Accordion/Accordion.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.container {
display: flex;
flex-flow: column nowrap;

align-items: stretch;
justify-content: stretch;
}

.content {
flex-grow: 1;
}
46 changes: 46 additions & 0 deletions src/components/Accordion/Accordion.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { render, screen } from '@testing-library/react';

import Accordion from './Accordion';

import type { TAccordionProps } from './Accordion.types';

beforeEach(() => {
window.scrollTo = jest.fn();
});

afterEach(() => {
jest.clearAllMocks();
});

const makeSut = ({
header = <div>header</div>,
content = <div>content</div>,
isOpen = false,
...props
}: Partial<TAccordionProps>) => {
return render(
<Accordion isOpen={isOpen} header={header} content={content} {...props} />
);
};

describe('Accordion', () => {
describe('when isOpen is false', () => {
it('body cannot render', () => {
makeSut({ isOpen: false });

const content = screen.queryByText('content');

expect(content).not.toBeInTheDocument();
});
});

describe('when isOpen is true', () => {
it('body can render', () => {
makeSut({ isOpen: true });

const content = screen.getByText('content');

expect(content).toBeVisible();
});
});
});
23 changes: 23 additions & 0 deletions src/components/Accordion/Accordion.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Story } from '@ladle/react';

import Accordion from './Accordion';

import { TAccordionProps } from './Accordion.types';

export const AccordionStories: Story<TAccordionProps> = (props) => {
return (
<Accordion
{...props}
duration={0.3}
isOpen
header={<button>Click to open!</button>}
content={
<div>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. od quis
molestias ab, voluptatem harum excepturi facere, necessitatibus
officiis. Officiis excepturi aperiam error.
</div>
}
/>
);
};
36 changes: 36 additions & 0 deletions src/components/Accordion/Accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import classNames from 'classnames';
import { AnimatePresence, motion } from 'framer-motion';

import styles from './Accordion.module.scss';

import { TAccordionProps } from './Accordion.types';

function computeVariants(duration: number) {
return {
expanded: { height: 'auto', transition: { duration } },
collapsed: { height: 0, transition: { duration } },
};
}

function Accordion(props: TAccordionProps) {
return (
<section className={classNames(props.className, styles.container)}>
<header className={styles.header}>{props.header}</header>
<AnimatePresence>
{props.isOpen && (
<motion.div
exit="collapsed"
animate="expanded"
initial="collapsed"
className={styles.content}
variants={computeVariants(props.duration ?? 0.3)}
>
{props.content}
</motion.div>
)}
</AnimatePresence>
</section>
);
}

export default Accordion;
9 changes: 9 additions & 0 deletions src/components/Accordion/Accordion.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ReactNode } from 'react';

export type TAccordionProps = {
className?: string;
duration?: number;
isOpen: boolean;
content: ReactNode;
header: ReactNode;
};
73 changes: 73 additions & 0 deletions src/components/Checkbox/Checkbox.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
@use '../../styles/global' as *;

.container {
display: flex;
flex-flow: row nowrap;

align-items: center;

font-family: $mainFont;

color: $secondaryPurple;

text-align: center;
font-size: 1.5rem;
font-weight: 500;

column-gap: 0.5rem;

cursor: pointer;
user-select: none;
}

.input {
width: 2rem;
height: 2rem;

display: block;

border: 2px solid $tertiaryGray;

position: relative;

background-color: $primaryWhite;
border-radius: 3px;

cursor: inherit;
appearance: none;

&:active,
&:checked:active {
border-color: $secondaryPurple;
}

&:checked {
border-color: $secondaryPurple;

background-color: $secondaryPurple;

&::after {
width: 100%;
height: 100%;

display: block;

position: absolute;
top: 0;
left: 0;

background-image: url('./assets/check.svg');
background-repeat: no-repeat;
background-position: center center;
background-size: cover;

content: '';
}
}
}

.text {
flex-grow: 1;

text-align: justify;
}
34 changes: 34 additions & 0 deletions src/components/Checkbox/Checkbox.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import Checkbox from './Checkbox';

import type { TCheckboxProps } from './Checkbox.types';

const makeSut = ({
onChange = jest.fn(),
checked = false,
...props
}: Partial<TCheckboxProps>) => {
return render(
<Checkbox checked={checked} onChange={onChange} {...props}>
checkbox
</Checkbox>
);
};

describe('Checkbox', () => {
describe('when checkbox be clicked', () => {
it('call [onChange] ', async () => {
const onChange = jest.fn();

makeSut({ onChange });

const input = screen.getByRole('checkbox');

await userEvent.click(input);

expect(onChange).toHaveBeenCalledWith(true);
});
});
});
9 changes: 9 additions & 0 deletions src/components/Checkbox/Checkbox.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Story } from '@ladle/react';

import Checkbox from './Checkbox';

import { TCheckboxProps } from './Checkbox.types';

export const CheckboxStories: Story<TCheckboxProps> = (props) => {
return <Checkbox {...props}>Checkbox</Checkbox>;
};
27 changes: 27 additions & 0 deletions src/components/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ChangeEventHandler } from 'react';

import classNames from 'classnames';

import styles from './Checkbox.module.scss';

import { TCheckboxProps } from './Checkbox.types';

function Checkbox(props: TCheckboxProps) {
const handleChange: ChangeEventHandler<HTMLInputElement> = ({
target: { checked },
}) => props.onChange(checked);

return (
<label className={classNames(styles.container, props.className)}>
<input
type="checkbox"
onChange={handleChange}
className={styles.input}
checked={props.checked}
/>
<span className={styles.text}>{props.children}</span>
</label>
);
}

export default Checkbox;
8 changes: 8 additions & 0 deletions src/components/Checkbox/Checkbox.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export type TCheckboxChangeHandler = (checked: boolean) => void;

export type TCheckboxProps = {
className?: string;
children: string;
onChange: TCheckboxChangeHandler;
checked: boolean;
};
3 changes: 3 additions & 0 deletions src/components/Checkbox/assets/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 35 additions & 0 deletions src/components/FirstComment/FirstComment.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
.container {
overflow: hidden;

display: flex;
flex-flow: column nowrap;

border: 1px solid #e6e1e6;

border-radius: 0 0 0 4px;
}

.checkbox {
padding: 1.125rem;
}

.textarea {
padding: 0.313rem;

// TODO: remove this when textarea be more customizable;
textarea {
width: 100%;
height: 12.5rem;

flex-grow: 1;

font-size: 1.5rem;

padding: 0.875rem;
border: 0;

outline: none;

resize: none;
}
}
34 changes: 34 additions & 0 deletions src/components/FirstComment/FirstComment.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import FirstComment from './FirstComment';

import type { TFirstCommentProps } from './FirstComment.types';

const makeSut = ({ ...props }: Partial<TFirstCommentProps>) => {
return render(<FirstComment {...props} />);
};

beforeEach(() => {
window.scrollTo = jest.fn();
});

afterEach(() => {
jest.clearAllMocks();
});

describe('FirstComment', () => {
describe('when checkbox is marked', () => {
it('open Accordion', async () => {
makeSut({});

const input = screen.getByRole('checkbox');

await userEvent.click(input);

const textarea = screen.getByPlaceholderText('Digite algo aqui...');

expect(textarea).toBeVisible();
});
});
});
9 changes: 9 additions & 0 deletions src/components/FirstComment/FirstComment.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Story } from '@ladle/react';

import FirstComment from './FirstComment';

import { TFirstCommentProps } from './FirstComment.types';

export const FirstCommentStories: Story<TFirstCommentProps> = (props) => {
return <FirstComment {...props} />;
};
Loading

0 comments on commit 07c6f2a

Please sign in to comment.