Skip to content

Commit

Permalink
[KLAR-8155] Add char counter to textarea (#536)
Browse files Browse the repository at this point in the history
* init

* renamne

* improve styles

* Empty-Commit

* update

* add tests

* fix typo
  • Loading branch information
matassp authored Dec 14, 2022
1 parent ba82080 commit a06f4a0
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 8 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@nordcloud/gnui",
"description": "Nordcloud Design System - a collection of reusable React components used in Nordcloud's SaaS products",
"version": "7.6.2",
"version": "7.7.0",
"license": "MIT",
"repository": {
"type": "git",
Expand Down
40 changes: 36 additions & 4 deletions src/components/textarea/Textarea.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import theme from "../../theme";

## Textarea properties

| properties | required | type | description |
| ---------: | :------: | :------------------------------------------- | :-------------------------------------- |
| status | false | <code>`success`</code>, <code>`error`</code> | color indicator status for SelectButton |
| small | false | boolean | small size styles |
| properties | required | type | description |
| -----------: | :------: | :------------------------------------------- | :-------------------------------------- |
| status | false | <code>`success`</code>, <code>`error`</code> | color indicator status for SelectButton |
| small | false | boolean | small size styles |
| maxCharCount | false | number | char counter limit |

## default

Expand Down Expand Up @@ -62,3 +63,34 @@ import theme from "../../theme";
}}
</Story>
</Canvas>

## maxCharCount

> `status`: `success | error` > `maxCharCount`: `100`
<Canvas>
<Story name="maxCharCount">
{() => {
const [status, setStatus] = React.useState("success");
return (
<GnuiContainer>
<GnuiContainer>
<Textarea status={status} maxCharCount={100} />
</GnuiContainer>
<Spacer height="1rem" />
<GnuiContainer>
<Button
size="small"
color={status === "error" ? "danger" : "success"}
onClick={() =>
setStatus(status === "danger" ? "success" : "danger")
}
>
Change status
</Button>
</GnuiContainer>
</GnuiContainer>
);
}}
</Story>
</Canvas>
45 changes: 44 additions & 1 deletion src/components/textarea/Textarea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Status } from "../input/types";

export type TextareaGroupProps = {
status?: Status;
maxCharCount?: number;
};

export type TextareaProps = React.InputHTMLAttributes<HTMLTextAreaElement> & {
Expand Down Expand Up @@ -80,10 +81,52 @@ const StyledTextarea = styled.textarea<TextareaProps>`
}
`;

const Counter = styled.p<TextareaGroupProps>`
color: ${theme.color.text.text03};
font-size: ${theme.fontSizes.sm};
text-align: right;
${({ status }) =>
status === "danger" &&
css`
color: ${theme.color.text.error};
`};
`;

const TextareaFlexContainer = styled.div`
display: flex;
flex-direction: column;
row-gap: ${theme.spacing.spacing01};
`;

type Props = TextareaGroupProps & TextareaProps;

export const Textarea = React.forwardRef<HTMLTextAreaElement, Props>(
({ status, ...props }, ref) => {
({ status, maxCharCount, ...props }, ref) => {
const [charCount, setCharCount] = React.useState(0);

function handleChange(event: React.ChangeEvent<HTMLTextAreaElement>) {
setCharCount(event.target.value.length);
props.onChange?.(event);
}

if (typeof maxCharCount === "number" && maxCharCount > 0) {
return (
<TextareaFlexContainer>
<TextareaGroup status={status}>
<StyledTextarea
ref={ref}
maxLength={maxCharCount}
{...props}
onChange={handleChange}
/>
</TextareaGroup>
<Counter status={status}>
{maxCharCount - charCount}&nbsp;&#47;&nbsp;{maxCharCount}
</Counter>
</TextareaFlexContainer>
);
}

return (
<TextareaGroup status={status}>
<StyledTextarea ref={ref} {...props} />
Expand Down
21 changes: 21 additions & 0 deletions src/components/textarea/__tests__/Textarea.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as React from "react";
import "@testing-library/jest-dom/extend-expect";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { Textarea } from "../Textarea";

test("displays correct character count", () => {
render(<Textarea maxCharCount={20} />);

expect(screen.getByText("20 / 20")).toBeInTheDocument();

userEvent.type(screen.getByRole("textbox"), "Strawberry");
expect(screen.getByText("10 / 20")).toBeInTheDocument();
});

// https://github.com/testing-library/user-event/issues/591#issuecomment-517816296
test("maxCharCount sets maxLength property", () => {
render(<Textarea maxCharCount={10} />);

expect(screen.getByRole("textbox")).toHaveProperty("maxLength");
});

0 comments on commit a06f4a0

Please sign in to comment.