From 35ba8fbad1e4ffc3bec0e066430c78f5fe629304 Mon Sep 17 00:00:00 2001 From: Ivan Ortega Alba Date: Thu, 5 Sep 2024 19:50:40 +0200 Subject: [PATCH] AutoSizeInput: Allow to be controlled by value (#92997) --- .../components/Input/AutoSizeInput.story.tsx | 6 +++++ .../components/Input/AutoSizeInput.test.tsx | 27 +++++++++++++++++++ .../src/components/Input/AutoSizeInput.tsx | 25 ++++++++++++++--- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/packages/grafana-ui/src/components/Input/AutoSizeInput.story.tsx b/packages/grafana-ui/src/components/Input/AutoSizeInput.story.tsx index f33faef0941..395c3232953 100644 --- a/packages/grafana-ui/src/components/Input/AutoSizeInput.story.tsx +++ b/packages/grafana-ui/src/components/Input/AutoSizeInput.story.tsx @@ -35,6 +35,8 @@ const meta: Meta = { suffixVisible: '', invalid: false, loading: false, + value: '', + defaultValue: '', }, argTypes: { prefixVisible: { @@ -80,6 +82,8 @@ export const Simple: StoryFn = (args) => { type={args.type} placeholder={args.placeholder} minWidth={args.minWidth} + value={args.value} + defaultValue={args.defaultValue} /> ); }; @@ -88,6 +92,8 @@ Simple.args = { before: false, after: false, placeholder: 'Enter your name here...', + value: '', + defaultValue: '', }; export default meta; diff --git a/packages/grafana-ui/src/components/Input/AutoSizeInput.test.tsx b/packages/grafana-ui/src/components/Input/AutoSizeInput.test.tsx index 64c34f1ba17..b47fc7da3d9 100644 --- a/packages/grafana-ui/src/components/Input/AutoSizeInput.test.tsx +++ b/packages/grafana-ui/src/components/Input/AutoSizeInput.test.tsx @@ -1,4 +1,5 @@ import { screen, render, fireEvent, waitFor } from '@testing-library/react'; +import { useEffect, useState } from 'react'; import { measureText } from '../../utils/measureText'; @@ -117,4 +118,30 @@ describe('AutoSizeInput', () => { expect(getComputedStyle(screen.getByTestId('input-wrapper')).width).toBe('32px'); }); + + it('should update the input value if the value prop changes', () => { + // Wrapper component to control the `value` prop + const Wrapper = () => { + const [value, setValue] = useState('Initial'); + + // Simulate prop change after render + useEffect(() => { + setTimeout(() => setValue('Updated'), 100); // Update `value` after 100ms + }, []); + + return ; + }; + + render(); + + const input: HTMLInputElement = screen.getByTestId('autosize-input'); + + // Check initial value + expect(input.value).toBe('Initial'); + + // Wait for the value to update + return waitFor(() => { + expect(input.value).toBe('Updated'); + }); + }); }); diff --git a/packages/grafana-ui/src/components/Input/AutoSizeInput.tsx b/packages/grafana-ui/src/components/Input/AutoSizeInput.tsx index c4fec7c6172..6e5b4ccd837 100644 --- a/packages/grafana-ui/src/components/Input/AutoSizeInput.tsx +++ b/packages/grafana-ui/src/components/Input/AutoSizeInput.tsx @@ -15,13 +15,32 @@ export interface Props extends InputProps { } export const AutoSizeInput = React.forwardRef((props, ref) => { - const { defaultValue = '', minWidth = 10, maxWidth, onCommitChange, onKeyDown, onBlur, ...restProps } = props; - const [value, setValue] = React.useState(defaultValue); + const { + defaultValue = '', + minWidth = 10, + maxWidth, + onCommitChange, + onKeyDown, + onBlur, + value: controlledValue, + ...restProps + } = props; + + // Initialize internal state + const [value, setValue] = React.useState(controlledValue ?? defaultValue); const [inputWidth, setInputWidth] = React.useState(minWidth); + // Update internal state when controlled `value` prop changes + useEffect(() => { + if (controlledValue !== undefined) { + setValue(controlledValue); + } + }, [controlledValue]); + + // Update input width when `value`, `minWidth`, or `maxWidth` change useEffect(() => { setInputWidth(getWidthFor(value.toString(), minWidth, maxWidth)); - }, [value, maxWidth, minWidth]); + }, [value, minWidth, maxWidth]); return (