From 42d689c6bc1bc5b7ba4f84b7c7ecefa2315456d2 Mon Sep 17 00:00:00 2001 From: roman Date: Mon, 10 Aug 2026 14:43:58 +0200 Subject: [PATCH] refactor(text-area): migrate TextArea from Flow to TypeScript --- .../{TextArea.js => TextArea.js.flow} | 0 src/components/text-area/TextArea.tsx | 99 +++++++++++++++++++ ...TextAreaField.js => TextAreaField.js.flow} | 0 src/components/text-area/TextAreaField.tsx | 29 ++++++ .../{TextArea.test.js => TextArea.test.tsx} | 2 +- ...eaField.test.js => TextAreaField.test.tsx} | 7 +- ...ea.test.js.snap => TextArea.test.tsx.snap} | 0 ...st.js.snap => TextAreaField.test.tsx.snap} | 0 .../text-area/{index.js => index.js.flow} | 0 src/components/text-area/index.ts | 4 + 10 files changed, 137 insertions(+), 4 deletions(-) rename src/components/text-area/{TextArea.js => TextArea.js.flow} (100%) create mode 100644 src/components/text-area/TextArea.tsx rename src/components/text-area/{TextAreaField.js => TextAreaField.js.flow} (100%) create mode 100644 src/components/text-area/TextAreaField.tsx rename src/components/text-area/__tests__/{TextArea.test.js => TextArea.test.tsx} (100%) rename src/components/text-area/__tests__/{TextAreaField.test.js => TextAreaField.test.tsx} (92%) rename src/components/text-area/__tests__/__snapshots__/{TextArea.test.js.snap => TextArea.test.tsx.snap} (100%) rename src/components/text-area/__tests__/__snapshots__/{TextAreaField.test.js.snap => TextAreaField.test.tsx.snap} (100%) rename src/components/text-area/{index.js => index.js.flow} (100%) create mode 100644 src/components/text-area/index.ts diff --git a/src/components/text-area/TextArea.js b/src/components/text-area/TextArea.js.flow similarity index 100% rename from src/components/text-area/TextArea.js rename to src/components/text-area/TextArea.js.flow diff --git a/src/components/text-area/TextArea.tsx b/src/components/text-area/TextArea.tsx new file mode 100644 index 0000000000..a7c2a5f445 --- /dev/null +++ b/src/components/text-area/TextArea.tsx @@ -0,0 +1,99 @@ +import * as React from 'react'; +import classNames from 'classnames'; +import uniqueId from 'lodash/uniqueId'; + +import Label from '../label'; +import Tooltip, { TooltipPosition, TooltipTheme, type TooltipProps } from '../tooltip'; + +import './TextArea.scss'; + +export interface TextAreaProps extends React.TextareaHTMLAttributes { + /** Add a class to the component */ + className?: string; + /** Description shown below the label */ + description?: React.ReactNode; + /** Error message shown in the error tooltip */ + error?: React.ReactNode; + /** Renders error tooltip at the specified position (positions are those from Tooltip) */ + errorTooltipPosition?: NonNullable; + /** Hides the label */ + hideLabel?: boolean; + /** Hides (optional) text from the label */ + hideOptionalLabel?: boolean; + /** Makes the text area value required */ + isRequired?: boolean; + /** Is text area resizable */ + isResizable?: boolean; + /** Label displayed for the text area */ + label: React.ReactNode; + /** Ref to the underlying textarea element. @TODO: eventually rename to innerRef for consistancy across all form elements */ + textareaRef?: React.Ref; + /** A CSS class for the tooltip's tether element component */ + tooltipTetherClassName?: string; +} + +const TextArea = ({ + className = '', + description, + error, + errorTooltipPosition, + hideLabel, + hideOptionalLabel, + isRequired, + isResizable, + label, + textareaRef, + tooltipTetherClassName, + ...rest +}: TextAreaProps) => { + const hasError = !!error; + const classes = classNames(className, 'text-area-container', { + 'show-error': hasError, + }); + + const errorMessageID = React.useRef(uniqueId('errorMessage')).current; + const descriptionID = React.useRef(uniqueId('description')).current; + + const ariaAttrs = { + 'aria-invalid': hasError, + 'aria-required': isRequired, + 'aria-errormessage': errorMessageID, + 'aria-describedby': description ? descriptionID : undefined, + }; + + return ( +
+