Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disabled: preserve input values when toggling the isDisabled prop #43508

Merged
merged 6 commits into from
Sep 8, 2022

Conversation

torounit
Copy link
Member

@torounit torounit commented Aug 23, 2022

What?

There is a bug in the Disabled component where changing isDisabled resets the form value. This has been fixed.

Why?

#42708 (review)

How?

Testing Instructions

  1. npm run storybook:dev
  2. Go to localhost:50240?path=/story/components-disabled--default
  3. Change isDisabled prop to false in controls.
  4. Change text box or select.
  5. Change isDisabled prop to true in controls.

Screenshots or screencast

2022-08-23.18.17.36.mov

@torounit torounit added [Type] Bug An existing feature does not function as intended [Package] Components /packages/components labels Aug 23, 2022
@torounit torounit changed the title Components: Disabled: Fixed so that the internal value is retained even if isDisabled is changed. Components: Disabled: Fixed so that the internal value remains when isDisabled is changed. Aug 23, 2022
@torounit torounit marked this pull request as ready for review August 23, 2022 09:26
@torounit torounit requested a review from ajitbohra as a code owner August 23, 2022 09:26
@torounit torounit requested a review from ciampo August 23, 2022 09:26
@ciampo ciampo changed the title Components: Disabled: Fixed so that the internal value remains when isDisabled is changed. Disabled: preserve input values when toggling the isDisabled prop Aug 23, 2022
Copy link
Contributor

@ciampo ciampo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code changes are looking good!

Interesting fix, I guess that using a div instead of a styled.div helps React's reconciliation and doesn't re-render the children input elements, throwing away their values (cc @mirka )

Could you also add a unit test, please?

Thank you!

packages/components/CHANGELOG.md Outdated Show resolved Hide resolved
@torounit
Copy link
Member Author

@ciampo Certainly a unit test is needed. I will add it.

@torounit torounit requested a review from ciampo August 23, 2022 15:58
@torounit torounit force-pushed the fix/components/disabled/keep-values branch from 9456046 to 264a92d Compare September 5, 2022 02:59
Comment on lines +163 to +166
expect( getInput() ).toHaveValue( 'This is input.' );
expect( getContentEditable() ).toHaveTextContent(
'This is contentEditable.'
);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If an instance previously obtained by screen.getByRole( 'textbox' ) is used, rerender is not reflected, so a new instance is obtained.

@torounit torounit requested a review from ciampo September 5, 2022 04:24
@torounit
Copy link
Member Author

torounit commented Sep 5, 2022

@ciampo Thanks for reviewing! Sorry for the delay in responding.

I have committed the fixed version.

Copy link
Contributor

@ciampo ciampo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🚀

I've got one more suggestion to make this fix less hacky:

Let's make the fix more explicit by refactoring that `div` inside a separate component
diff --git a/packages/components/src/disabled/index.tsx b/packages/components/src/disabled/index.tsx
index bcdbf4ba48..dcaef3e173 100644
--- a/packages/components/src/disabled/index.tsx
+++ b/packages/components/src/disabled/index.tsx
@@ -1,8 +1,13 @@
+/**
+ * External dependencies
+ */
+import type { TdHTMLAttributes, HTMLProps } from 'react';
+
 /**
  * WordPress dependencies
  */
 import { useDisabled } from '@wordpress/compose';
-import { createContext } from '@wordpress/element';
+import { createContext, forwardRef } from '@wordpress/element';
 
 /**
  * Internal dependencies
@@ -15,6 +20,15 @@ import { useCx } from '../utils';
 const Context = createContext< boolean >( false );
 const { Consumer, Provider } = Context;
 
+// Extracting this ContentWrapper component in order to make it more explicit
+// the same 'ContentWrapper' component is needed so that React can reconcile
+// the dom correctly when switching between disabled/non-disabled (instead
+// of thrashing the previous DOM and therefore losing the form fields values).
+const ContentWrapper = forwardRef<
+	HTMLDivElement,
+	HTMLProps< HTMLDivElement >
+>( ( props, ref ) => <div { ...props } ref={ ref } /> );
+
 /**
  * `Disabled` is a component which disables descendant tabbable elements and prevents pointer interaction.
  *
@@ -56,14 +70,14 @@ function Disabled( {
 	if ( ! isDisabled ) {
 		return (
 			<Provider value={ false }>
-				<div>{ children }</div>
+				<ContentWrapper>{ children }</ContentWrapper>
 			</Provider>
 		);
 	}
 
 	return (
 		<Provider value={ true }>
-			<div
+			<ContentWrapper
 				ref={ ref }
 				className={ cx(
 					disabledStyles,
@@ -73,7 +87,7 @@ function Disabled( {
 				{ ...props }
 			>
 				{ children }
-			</div>
+			</ContentWrapper>
 		</Provider>
 	);
 }

@torounit torounit merged commit ef6ba1a into trunk Sep 8, 2022
@torounit torounit deleted the fix/components/disabled/keep-values branch September 8, 2022 06:54
@github-actions github-actions bot added this to the Gutenberg 14.1 milestone Sep 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] Components /packages/components [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants