Skip to content
Snippets Groups Projects
Commit 6788eb99 authored by Alissa Cheng's avatar Alissa Cheng
Browse files

Merge branch 'SDC-1248/add-text-area-to-design-system' into 'main'

Add TextArea component based on NextUI Textarea

See merge request !26
parents 95f77718 bfe4f0ca
No related branches found
No related tags found
1 merge request!26Add TextArea component based on NextUI Textarea
Pipeline #73679 passed
import { Textarea } from "@nextui-org/react";
import { TextInputProps } from "./TextInput";
import { baseInputClassNames } from "./utils/baseComponents";
interface TextAreaProps extends Omit<TextInputProps, OmittedTextInputProps> {
minRows?: number;
maxRows?: number;
disableAutosize?: boolean;
}
type OmittedTextInputProps = "isClearable";
const TextArea = ({
isRequired = false,
isDisabled = false,
isReadOnly = false,
label = "",
minRows = 3,
maxRows = 8,
maxLength,
value,
onValueChange,
isInvalid = false,
errorMessage,
disableAutosize = false,
}: TextAreaProps) => {
const hasClearButton = false;
const hasMainWrapper = false;
return (
<Textarea
isRequired={isRequired}
isDisabled={isDisabled}
isReadOnly={isReadOnly}
label={label}
minRows={minRows}
maxRows={maxRows}
maxLength={maxLength}
value={value}
onValueChange={onValueChange}
isInvalid={isInvalid}
errorMessage={errorMessage}
disableAutosize={disableAutosize}
labelPlacement="outside"
variant="bordered"
classNames={{
...baseInputClassNames(isDisabled, hasMainWrapper, hasClearButton),
input: disableAutosize && "resize-y",
}}
></Textarea>
);
};
export default TextArea;
...@@ -68,3 +68,4 @@ const TextInput = ({ ...@@ -68,3 +68,4 @@ const TextInput = ({
}; };
export default TextInput; export default TextInput;
export type { TextInputProps };
...@@ -42,7 +42,9 @@ type BaseInputProps = { ...@@ -42,7 +42,9 @@ type BaseInputProps = {
type baseInputClassNamesObj = { [key in InputSlots]: string }; type baseInputClassNamesObj = { [key in InputSlots]: string };
export const baseInputClassNames = ( export const baseInputClassNames = (
isDisabled: boolean isDisabled: boolean,
hasMainWrapper: boolean = true, // for some components (i.e., textarea) the inputwrapper is the main wrapper,
hasClearButton: boolean = true
): baseInputClassNamesObj => { ): baseInputClassNamesObj => {
// this is the border color (use text-*) // this is the border color (use text-*)
const mainWrapperClass = (isDisabled: boolean) => const mainWrapperClass = (isDisabled: boolean) =>
...@@ -64,9 +66,13 @@ export const baseInputClassNames = ( ...@@ -64,9 +66,13 @@ export const baseInputClassNames = (
base: cursorPointer(isDisabled), base: cursorPointer(isDisabled),
label: "!text-foreground-body", label: "!text-foreground-body",
input: "!text-foreground-body bg-default", input: "!text-foreground-body bg-default",
inputWrapper: clsx("px-2 rounded-[4px]", formFieldBg(isDisabled)), inputWrapper: clsx(
mainWrapper: mainWrapperClass(isDisabled), "px-2 rounded-[4px]",
clearButton: clearButtonClass(isDisabled), formFieldBg(isDisabled),
!hasMainWrapper && mainWrapperClass(isDisabled)
),
mainWrapper: hasMainWrapper && mainWrapperClass(isDisabled),
clearButton: hasClearButton && clearButtonClass(isDisabled),
} as baseInputClassNamesObj; } as baseInputClassNamesObj;
}; };
......
...@@ -12,6 +12,7 @@ export { default as ProgressBar } from "./components/ProgressBar"; ...@@ -12,6 +12,7 @@ export { default as ProgressBar } from "./components/ProgressBar";
export { default as Radio } from "./components/Radio"; export { default as Radio } from "./components/Radio";
export { default as Slider } from "./components/Slider"; export { default as Slider } from "./components/Slider";
export { default as Table } from "./components/Table"; export { default as Table } from "./components/Table";
export { default as TextArea } from "./components/TextArea";
export { default as TextInput } from "./components/TextInput"; export { default as TextInput } from "./components/TextInput";
export { default as Toggle } from "./components/Toggle"; export { default as Toggle } from "./components/Toggle";
export { default as Typography } from "./components/Typography"; export { default as Typography } from "./components/Typography";
import { Meta } from "@storybook/react";
import { useMemo, useState } from "react";
import TextArea from "src/components/TextArea.tsx";
const meta = {
title: "Components/Text Area",
component: TextArea,
} satisfies Meta;
export default meta;
export const Default = () => {
const [value, setValue] = useState("");
return (
<TextArea
label="Some long story goes here."
value={value}
onValueChange={setValue}
></TextArea>
);
};
export const CustomValidation = () => {
const [value, setValue] = useState("");
const validateOnlyCapitals = (str: string) => str.match(/^[A-Z]+/g);
const isInvalid = useMemo(() => {
if (value === "") return false;
return !validateOnlyCapitals(value);
}, [value]);
return (
<TextArea
label="Only capitals"
value={value}
onValueChange={setValue}
isInvalid={isInvalid}
errorMessage={isInvalid ? "Only capitals are allowed!" : ""}
/>
);
};
export const Required = () => {
const [value, setValue] = useState("");
return (
<TextArea
label="I require a value"
isRequired={true}
value={value}
onValueChange={setValue}
/>
);
};
export const Disabled = () => {
return (
<TextArea
label="You can't interact with this component!"
isDisabled={true}
value="*Evil laughter*"
/>
);
};
export const ReadOnly = () => {
return (
<TextArea
label="You can't change this value!"
isReadOnly={true}
value="*Neutral laughter*"
/>
);
};
export const MaxLength = () => {
const [value, setValue] = useState("");
return (
<TextArea
label="Maximum of 100 characters"
maxLength={100}
value={value}
onValueChange={setValue}
/>
);
};
export const MaxRows = () => {
const [value, setValue] = useState("");
return (
<TextArea
label="Maximum of 2 rows"
maxRows={2}
value={value}
onValueChange={setValue}
/>
);
};
export const MinRows = () => {
const [value, setValue] = useState("");
return (
<TextArea
label="Minimum of 3 rows"
maxRows={3}
value={value}
onValueChange={setValue}
/>
);
};
export const DisableAutoSize = () => {
const [value, setValue] = useState("");
return (
<TextArea
label="Autosize is disabled"
disableAutosize={true}
value={value}
onValueChange={setValue}
/>
);
};
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment