From 856cffb5d4cbecf2e26eaa5c9b7553018890b9fb Mon Sep 17 00:00:00 2001 From: Artur Santiago Date: Tue, 21 Jan 2025 18:33:10 -0300 Subject: [PATCH] feat: create TextareaField component --- packages/components/src/index.ts | 2 + .../molecules/TextareaField/TextareaField.tsx | 100 +++++++++++++ .../src/molecules/TextareaField/index.ts | 2 + .../molecules/TextareaField/styles.scss | 137 ++++++++++++++++++ 4 files changed, 241 insertions(+) create mode 100644 packages/components/src/molecules/TextareaField/TextareaField.tsx create mode 100644 packages/components/src/molecules/TextareaField/index.ts create mode 100644 packages/ui/src/components/molecules/TextareaField/styles.scss diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index f33626bc91..3df34b2c85 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -108,6 +108,8 @@ export type { } from './molecules/Gift' export { default as InputField } from './molecules/InputField' export type { InputFieldProps } from './molecules/InputField' +export { default as TextareaField } from './molecules/TextareaField' +export type { TextareaFieldProps } from './molecules/TextareaField' export { default as LinkButton } from './molecules/LinkButton' export type { LinkButtonProps } from './molecules/LinkButton' export { default as Modal, ModalHeader, ModalBody } from './molecules/Modal' diff --git a/packages/components/src/molecules/TextareaField/TextareaField.tsx b/packages/components/src/molecules/TextareaField/TextareaField.tsx new file mode 100644 index 0000000000..f07185fa34 --- /dev/null +++ b/packages/components/src/molecules/TextareaField/TextareaField.tsx @@ -0,0 +1,100 @@ +import type { MutableRefObject } from 'react' +import React, { useEffect, useRef } from 'react' + +import type { TextareaProps } from '../..' +import { Textarea, Label } from '../..' + +type DefaultProps = { + /** + * ID to find this component in testing tools (e.g.: cypress, testing library, and jest). + */ + testId?: string + /** + * ID to identify textarea and corresponding label. + */ + id: string + /** + * The text displayed to identify textarea text. + */ + label: string + /** + * The error message is displayed when an error occurs. + */ + error?: string + /** + * Component's ref. + */ + textareaRef?: MutableRefObject + /** + * Specifies that the whole textarea component should be disabled. + */ + disabled?: boolean +} + +export type TextareaFieldProps = DefaultProps & + Omit + +const TextareaField = ({ + id, + label, + error, + placeholder = ' ', // initializes with an empty space to style float label using `placeholder-shown` + textareaRef, + disabled, + value, + testId = 'fs-textarea-field', + ...otherProps +}: TextareaFieldProps) => { + const shouldDisplayError = !disabled && error && error !== '' + const textareaInternalRef = useRef(null) + const ref = textareaRef || textareaInternalRef + + useEffect(() => { + const textarea = ref?.current + if (!textarea) return + + const updateSize = () => { + textarea.parentElement?.style.setProperty( + '--fs-textarea-width', + `${textarea.offsetWidth}px` + ) + textarea.parentElement?.style.setProperty( + '--fs-textarea-height', + `${textarea.offsetHeight}px` + ) + } + + updateSize() + + const resizeObserver = new ResizeObserver(updateSize) + resizeObserver.observe(textarea) + + return () => { + resizeObserver.disconnect() + } + }, [ref]) + + return ( +
+