Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions assets/index.less
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
@textarea-prefix-cls: rc-textarea;

.rc-textarea-affix-wrapper {
display: inline-block;
box-sizing: border-box;

textarea {
box-sizing: border-box;
width: 100%;
height: 100%;
padding: 0;
border: 1px solid #1677ff;
}
}
8 changes: 8 additions & 0 deletions docs/demo/showCount.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable no-console */
import Textarea from 'rc-textarea';
import React, { useState } from 'react';
import '../../assets/index.less';

export default function App() {
const [value, setValue] = useState('hello\nworld');
Expand All @@ -18,6 +19,13 @@ export default function App() {
<Textarea autoSize showCount />
<p>controlled</p>
<Textarea value={value} onChange={onChange} showCount maxLength={100} />
<p>with height</p>
<Textarea
value={value}
onChange={onChange}
showCount
style={{ height: 200, width: '100%', resize: 'vertical' }}
/>
</div>
);
}
15 changes: 14 additions & 1 deletion src/TextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const TextArea = React.forwardRef<TextAreaRef, TextAreaProps>(
hidden,
classNames,
styles,
onResize,
...rest
},
ref,
Expand All @@ -75,6 +76,7 @@ const TextArea = React.forwardRef<TextAreaRef, TextAreaProps>(
const [compositing, setCompositing] = React.useState(false);
const oldCompositionValueRef = React.useRef<string>();
const oldSelectionStartRef = React.useRef<number>(0);
const [textareaResized, setTextareaResized] = React.useState<boolean>(null);

const focus = () => {
resizableTextAreaRef.current.textArea.focus();
Expand Down Expand Up @@ -217,6 +219,13 @@ const TextArea = React.forwardRef<TextAreaRef, TextAreaProps>(
);
}

const handleResize: TextAreaProps['onResize'] = (size) => {
onResize?.(size);
if (resizableTextAreaRef.current.textArea.style.height) {
setTextareaResized(true);
}
};

const textarea = (
<BaseInput
value={val}
Expand All @@ -233,7 +242,10 @@ const TextArea = React.forwardRef<TextAreaRef, TextAreaProps>(
disabled={disabled}
focused={focused}
className={className}
style={style}
style={{
...style,
...(textareaResized ? { height: 'auto' } : {}),
}}
dataAttrs={{
affixWrapper: {
'data-count': typeof dataCount === 'string' ? dataCount : undefined,
Expand All @@ -253,6 +265,7 @@ const TextArea = React.forwardRef<TextAreaRef, TextAreaProps>(
style={{ ...styles?.textarea, resize: style?.resize }}
disabled={disabled}
prefixCls={prefixCls}
onResize={handleResize}
ref={resizableTextAreaRef}
/>
}
Expand Down
48 changes: 22 additions & 26 deletions tests/index.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,11 @@
import { act, fireEvent, render } from '@testing-library/react';
import {
_rs as onEsResize,
_rs as onLibResize,
} from 'rc-resize-observer/lib/utils/observerUtil';
import { fireEvent, render } from '@testing-library/react';
import React from 'react';
import type { TextAreaProps } from '../src';
import TextArea from '../src';
import calculateAutoSizeStyle, {
calculateNodeStyling,
} from '../src/calculateNodeHeight';

async function wait() {
for (let i = 0; i < 100; i += 1) {
await act(async () => {
jest.runAllTimers();
await Promise.resolve();
});
}
}

function triggerResize(target) {
const originGetBoundingClientRect = target.getBoundingClientRect;

target.getBoundingClientRect = () => ({ width: 510, height: 903 });
// @ts-ignore
onLibResize([{ target }]);
// @ts-ignore
onEsResize([{ target }]);

target.getBoundingClientRect = originGetBoundingClientRect;
}
import { triggerResize, wait } from './utils';

describe('TextArea', () => {
const originalGetComputedStyle = window.getComputedStyle;
Expand Down Expand Up @@ -396,4 +372,24 @@ describe('TextArea', () => {
);
expect(container).toMatchSnapshot();
});

it('should be resized with textarea', async () => {
const onResize = jest.fn();
const { container } = render(
<TextArea onResize={onResize} showCount style={{ height: 200 }} />,
);
await wait();
expect(
(container.querySelector('.rc-textarea-affix-wrapper') as HTMLDivElement)
.style.height,
).toBe('200px');

triggerResize(container.querySelector('textarea'), { height: 1000 });
await wait();
expect(onResize).toHaveBeenCalledTimes(1);
expect(
(container.querySelector('.rc-textarea-affix-wrapper') as HTMLDivElement)
.style.height,
).toBe('auto');
});
});
31 changes: 31 additions & 0 deletions tests/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { act } from '@testing-library/react';
import {
_rs as onEsResize,
_rs as onLibResize,
} from 'rc-resize-observer/lib/utils/observerUtil';

export function triggerResize(
target,
size?: { width?: number; height?: number },
) {
const { width = 510, height = 903 } = size || {};
const originGetBoundingClientRect = target.getBoundingClientRect;

target.getBoundingClientRect = () => ({ width, height });
// @ts-ignore
onLibResize([{ target }]);
// @ts-ignore
onEsResize([{ target }]);

target.style.height = `${height}px`;
target.getBoundingClientRect = originGetBoundingClientRect;
}

export async function wait() {
for (let i = 0; i < 100; i += 1) {
await act(async () => {
jest.runAllTimers();
await Promise.resolve();
});
}
}