-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
feat(NumberInput): controlled upon onChange prop #2730
feat(NumberInput): controlled upon onChange prop #2730
Conversation
This change turns `<NumberInput>` to "controlled mode", if `onChange` prop exists. Refs carbon-design-system#2489.
@@ -78,6 +84,18 @@ module.exports = (baseConfig, env, defaultConfig) => { | |||
], | |||
}; | |||
|
|||
defaultConfig.module.rules.push({ | |||
test: /(\/|\\)FeatureFlags\.js$/, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Flipping the switch upon React context is in consideration, for the time once we have finished implementing this mechanism to all form components.
@@ -13,6 +13,7 @@ import WarningFilled16 from '@carbon/icons-react/lib/warning--filled/16'; | |||
import CaretDownGlyph from '@carbon/icons-react/lib/caret--down/index'; | |||
import CaretUpGlyph from '@carbon/icons-react/lib/caret--up/index'; | |||
import mergeRefs from '../../tools/mergeRefs'; | |||
import { useControlledStateWithEventListener } from '../../internal/FeatureFlags'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Flipping the switch upon React context is in consideration, for the time once we have finished implementing this mechanism to all form components.
@@ -17,4 +17,4 @@ | |||
* const MyComponent = props => (<div {...props}>{aFeatureFlag ? 'foo' : 'bar'}</div>); | |||
*/ | |||
|
|||
/* Currently no feature flag is in use, but keeping this file as a placeholder */ | |||
export const useControlledStateWithEventListener = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Flipping the switch upon React context is in consideration, for the time once we have finished implementing this mechanism to all form components.
Deploy preview for the-carbon-components ready! Built with commit fd59103 https://deploy-preview-2730--the-carbon-components.netlify.com |
Deploy preview for carbon-components-react ready! Built with commit fd59103 https://deploy-preview-2730--carbon-components-react.netlify.com |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we expose a storybook example for the controlled component?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good to me!
@asudoh I'm not sure . Wouldn't doing so mean that inputs would need to be controlled or uncontrolled application-wide? Wrapping individual inputs or even forms in context seems like a really tedious API for developers to use. I think we should focus on making the components themselves flexible, whether that means a distinct controlled/presentational component as we discussed previously, or the controlled mode implementation I used for the UI Shell. Slightly off topic, but I'd also like to reiterate my aversion towards putting logic in gDSFP for the reasons outlined here: #2489 |
@@ -254,7 +265,10 @@ class NumberInput extends Component { | |||
min, | |||
step, | |||
onChange: this.handleChange, | |||
value: this.state.value, | |||
value: | |||
useControlledStateWithEventListener && this.props.onChange |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the presence of an onChange
prop should be the switch that turns on controlled mode. There's many cases where developers would want to be informed 'onChange' but not control the actual value of the input themselves. Things like clearing form validation notifications, displaying computed values from inputs etc.
My initial guess at what the a control-mode trigger would look like is: defaultValue, value, and onChange. If value is supplied, then the component is controlled. Ideally, this is controlled using a ref so the controlled/uncontrolled nature of the component persists for it's lifecycle. I think it would be a good pattern to establish the controlled/uncontrolled status of a component in a single location rather than using Also, now that I finally understand what the feature flag is meant to accomplish, I think we should reconsider the name. We might want to avoid naming new things with the prefix use as this is this the naming standard for custom hooks. A more appropriate name might also leave out the already implied implementation. Maybe something like |
Thanks @vpicone for reviewing!
Would it be this "if all of those props are given", or "if any of those props are given"?
Makes sense! |
@asudoh Sorry I didn't meant to imply any requirements there I should have been more clear. Here's better descriptions with one additional prop:
Warning: Failed `NumberInput` propType: You provided a value prop to `NumberInput`
without an `onChange` handler. This will render a read-only field. If the field
should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`. This warning assumes the developer meant for the component to be uncontrolled and intended to set a default value.
|
Thanks @vpicone for the details! Sounds good basically, just one thing - |
@asudoh I haven't read that PR all the way, but while the readOnly prop acts as a 'supressWarning' it also maps to an actual form input attribute (which was mentioned in the PR). This attribute has beneficial accessibility implications when a developer is in read only mode: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#readonly It indicates to screen readers that the input should:
So while additional styling might be nice eventually, its not necessary for a11y. I can't think of a more appropriate prop at the moment. This one serves the purpose of ensuring the developer has intentionally engaged 'readOnly' mode while also ensuring the read-only input is accessible. If given the readOnly prop, the input would need to forgo all state changes. I think it's important to avoid the case where users changes aren't doing anything, which I remember was a concern of yours. |
@vpicone Great point on The former is
They are similar to Does it make sense? If so, and unless @carbon-design-system/design disagrees, we can apply some of styles of disabled number input style if |
@asudoh It does. Since we've determined the onChange handler might not suffice as the marker for controlled mode, a readOnly state is inevitable. Regardless, we should be supporting this native input state as close to the native input as possible I believe would address #2177 along with all the other types of input for which we have a controlled mode going forward. It might make sense to duplicate the styles into a separate token in case we need to differentiate the styles going forward, but I agree that we should try to stick as closely to the native implementation as possible in regards to text color fading and controls disappearing. |
Superseded by: #3028 |
This change turns
<NumberInput>
to "controlled mode", ifonChange
prop exists.Refs #2489.
Changelog
New
<NumberInput>
to "controlled mode", ifonChange
prop exists.Testing / Reviewing
Testing should make sure
<NumberInput>
is not broken.