Skip to content

Commit d12b4ac

Browse files
committed
fix(textInput): Use resizeObserver to trigger trimLeft calculation
Fixes #4710
1 parent 3d8b463 commit d12b4ac

2 files changed

Lines changed: 95 additions & 7 deletions

File tree

‎packages/react-core/src/components/TextInput/TextInput.tsx‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import * as React from 'react';
22
import styles from '@patternfly/react-styles/css/components/FormControl/form-control';
33
import { css } from '@patternfly/react-styles';
44
import { ValidatedOptions } from '../../helpers/constants';
5-
import { debounce, trimLeft, canUseDOM } from '../../helpers/util';
5+
import { trimLeft } from '../../helpers/util';
66
import { getDefaultOUIAId, getOUIAProps, OUIAProps } from '../../helpers';
7+
import { getResizeObserver } from '../../helpers/resizeObserver';
78

89
export enum TextInputTypes {
910
text = 'text',
@@ -89,6 +90,7 @@ export class TextInputBase extends React.Component<TextInputProps, TextInputStat
8990
ouiaSafe: true
9091
};
9192
inputRef = React.createRef<HTMLInputElement>();
93+
observer: any = () => {};
9294

9395
constructor(props: TextInputProps) {
9496
super(props);
@@ -109,18 +111,15 @@ export class TextInputBase extends React.Component<TextInputProps, TextInputStat
109111

110112
componentDidMount() {
111113
if (this.props.isLeftTruncated) {
114+
const inputRef = this.props.innerRef || this.inputRef;
115+
this.observer = getResizeObserver(inputRef.current, this.handleResize);
112116
this.handleResize();
113-
if (canUseDOM) {
114-
window.addEventListener('resize', debounce(this.handleResize, 250));
115-
}
116117
}
117118
}
118119

119120
componentWillUnmount() {
120121
if (this.props.isLeftTruncated) {
121-
if (canUseDOM) {
122-
window.removeEventListener('resize', debounce(this.handleResize, 250));
123-
}
122+
this.observer();
124123
}
125124
}
126125

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import * as React from 'react';
2+
import { canUseDOM } from './util';
3+
4+
/**
5+
* This function creates a ResizeObserver used to handle resize events for the given containerRef. If ResizeObserver
6+
* or the given containerRef are not available, a window resize event listener is used by default.
7+
*
8+
* Example 1:
9+
*
10+
* private containerRef = React.createRef<HTMLDivElement>();
11+
* private observer: any = () => {};
12+
*
13+
* public componentDidMount() {
14+
* this.observer = getResizeObserver(this.containerRef.current, this.handleResize);
15+
* }
16+
*
17+
* public componentWillUnmount() {
18+
* this.observer();
19+
* }
20+
*
21+
* private handleResize = () => {
22+
* if (this.containerRef.current && this.containerRef.current.clientWidth) {
23+
* this.setState({ width: this.containerRef.current.clientWidth });
24+
* }
25+
* };
26+
*
27+
* public render() {
28+
* return (
29+
* <div ref={this.containerRef} >
30+
* <Chart width={this.state.width} ... />
31+
* </div>
32+
* );
33+
* }
34+
*
35+
* Example 2:
36+
*
37+
* private inputRef = React.createRef<HTMLInputElement>();
38+
* private observer: any = () => {};
39+
*
40+
* public componentDidMount() {
41+
* this.observer = getResizeObserver(this.inputRef.current, this.handleResize);
42+
* }
43+
*
44+
* public componentWillUnmount() {
45+
* this.observer();
46+
* }
47+
*
48+
* private handleResize = () => {
49+
* if (this.inputRef.current) {
50+
* trimLeft(inputRef.current, String(this.props.value));
51+
* }
52+
* };
53+
*
54+
* public render() {
55+
* return (
56+
* <input ref={this.inputRef} ... />
57+
* );
58+
* }
59+
*
60+
* @param {React.RefObject} containerRef The container reference to observe
61+
* @param {Function} handleResize The function to call for resize events
62+
* @return {Function} The function used to unobserve resize events
63+
*/
64+
export const getResizeObserver = (containerRef: React.RefObject<any>, handleResize: () => void) => {
65+
const { ResizeObserver } = canUseDOM ? (window as any) : undefined;
66+
let unobserve: any;
67+
68+
if (containerRef && ResizeObserver) {
69+
const resizeObserver = new ResizeObserver((entries: any) => {
70+
// Wrap resize function in requestAnimationFrame to avoid "ResizeObserver loop limit exceeded" errors
71+
window.requestAnimationFrame(() => {
72+
if (Array.isArray(entries) && entries.length > 0) {
73+
handleResize();
74+
}
75+
});
76+
});
77+
resizeObserver.observe(containerRef);
78+
unobserve = () => resizeObserver.unobserve(containerRef);
79+
} else if (canUseDOM) {
80+
window.addEventListener('resize', handleResize);
81+
unobserve = () => window.removeEventListener('resize', handleResize);
82+
}
83+
84+
return () => {
85+
if (unobserve) {
86+
unobserve();
87+
}
88+
};
89+
};

0 commit comments

Comments
 (0)