Skip to content

Commit

Permalink
feat: forward ref for <TextArea> (#2148)
Browse files Browse the repository at this point in the history
* feat: forward ref for `<TextArea>`

* Create odd-pens-exist.md
  • Loading branch information
sebald authored Jun 8, 2022
1 parent 2e68896 commit 33c54b3
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 66 deletions.
5 changes: 5 additions & 0 deletions .changeset/odd-pens-exist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@marigold/components": minor
---

feat: forward ref for `<TextArea>`
13 changes: 13 additions & 0 deletions packages/components/src/TextArea/TextArea.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,16 @@ export default {
export const Basic: ComponentStory<typeof TextArea> = args => (
<TextArea {...args} />
);

export const Controlled: ComponentStory<typeof TextArea> = args => {
const [value, setValue] = React.useState('');
return (
<>
<TextArea {...args} value={value} onChange={setValue} />
<pre>
<strong>Input Value:</strong>
{value}
</pre>
</>
);
};
11 changes: 11 additions & 0 deletions packages/components/src/TextArea/TextArea.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -299,3 +299,14 @@ test('can be controlled', () => {
userEvent.type(screen.getByTestId('textarea'), 'Hello there!');
expect(screen.getByTestId('output')).toHaveTextContent('Hello there!');
});

test('forwards ref', () => {
const ref = React.createRef<HTMLTextAreaElement>();
render(
<ThemeProvider theme={theme}>
<TextArea data-testid="text-area" label="A Label" ref={ref} />
</ThemeProvider>
);

expect(ref.current).toBeInstanceOf(HTMLTextAreaElement);
});
138 changes: 72 additions & 66 deletions packages/components/src/TextArea/TextArea.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import React, { useRef } from 'react';
import React, { forwardRef } from 'react';
import { useHover } from '@react-aria/interactions';
import { useFocusRing } from '@react-aria/focus';
import { useTextField } from '@react-aria/textfield';
import { useObjectRef } from '@react-aria/utils';
import { AriaTextFieldProps } from '@react-types/textfield';

import {
Expand All @@ -11,8 +14,6 @@ import {
import { ComponentProps } from '@marigold/types';

import { FieldBase, FieldBaseProps } from '../FieldBase';
import { useHover } from '@react-aria/interactions';
import { useFocusRing } from '@react-aria/focus';

// Theme Extension
// ---------------
Expand Down Expand Up @@ -54,69 +55,74 @@ export interface TextAreaProps

// Component
// ---------------
export const TextArea = ({
variant,
size,
width,
disabled,
required,
readOnly,
error,
rows,
...props
}: TextAreaProps) => {
const { label, description, errorMessage } = props;
const ref = useRef<HTMLTextAreaElement>(null);
export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
(
{
variant,
size,
width,
disabled,
required,
readOnly,
error,
rows,
...props
},
ref
) => {
const { label, description, errorMessage } = props;
const textAreaRef = useObjectRef(ref);

const { labelProps, inputProps, descriptionProps, errorMessageProps } =
useTextField(
{
inputElementType: 'textarea',
isDisabled: disabled,
isRequired: required,
isReadOnly: readOnly,
validationState: error ? 'invalid' : 'valid',
...props,
},
ref
);
const { labelProps, inputProps, descriptionProps, errorMessageProps } =
useTextField(
{
inputElementType: 'textarea',
isDisabled: disabled,
isRequired: required,
isReadOnly: readOnly,
validationState: error ? 'invalid' : 'valid',
...props,
},
textAreaRef
);

const { hoverProps, isHovered } = useHover({});
const { focusProps, isFocusVisible } = useFocusRing();
const stateProps = useStateProps({
hover: isHovered,
focus: isFocusVisible,
disabled,
readOnly,
error,
});
const { hoverProps, isHovered } = useHover({});
const { focusProps, isFocusVisible } = useFocusRing();
const stateProps = useStateProps({
hover: isHovered,
focus: isFocusVisible,
disabled,
readOnly,
error,
});

const styles = useComponentStyles('TextArea', { variant, size });
return (
<FieldBase
label={label}
labelProps={labelProps}
required={required}
description={description}
descriptionProps={descriptionProps}
error={error}
errorMessage={errorMessage}
errorMessageProps={errorMessageProps}
stateProps={stateProps}
variant={variant}
size={size}
width={width}
>
<Box
as="textarea"
css={styles}
ref={ref}
rows={rows}
{...inputProps}
{...focusProps}
{...hoverProps}
{...stateProps}
/>
</FieldBase>
);
};
const styles = useComponentStyles('TextArea', { variant, size });
return (
<FieldBase
label={label}
labelProps={labelProps}
required={required}
description={description}
descriptionProps={descriptionProps}
error={error}
errorMessage={errorMessage}
errorMessageProps={errorMessageProps}
stateProps={stateProps}
variant={variant}
size={size}
width={width}
>
<Box
as="textarea"
css={styles}
ref={textAreaRef}
rows={rows}
{...inputProps}
{...focusProps}
{...hoverProps}
{...stateProps}
/>
</FieldBase>
);
}
);

0 comments on commit 33c54b3

Please sign in to comment.