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

New NumberControl component #13863

Closed
wants to merge 19 commits into from

Conversation

m-e-h
Copy link
Member

@m-e-h m-e-h commented Feb 13, 2019

Description

Adds a <NumberControl> component for use in other components and blocks.

Would reduce duplicate code and create a consistent style across existing components that are creating their own number inputs. Currently, this would be font-size-picker, focal-point-picker, and range-control that I know of. Probably others.

Types of changes

New feature (non-breaking change which adds functionality)

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.

Inspired by #13709 and #11555

@m-e-h
Copy link
Member Author

m-e-h commented Feb 13, 2019

Not sure if I should update existing components in the same PR or if they should be done individually after the NumberControl component is merged.
I've added them here to make it easier to test but they can be removed.

Copy link
Member

@jorgefilipecosta jorgefilipecosta left a comment

Choose a reason for hiding this comment

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

Thank you for your contribution @m-e-h, I think it may make sense to expose a very simple component that just renders a number input field.
Using it as the basis for other components may make the work of creating reactive native components simpler as it reduces direct dom usage.
But I would like more thoughts about creating a new component cc: @youknowriad

value={ this.fractionToPercentage( percentages.x ) }
/>

<NumberControl
Copy link
Member

Choose a reason for hiding this comment

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

It looks like here we have a NumberControl inside a BaseControl. NumberControl renders its own BaseControl component so I think the existing BaseControl can also be removed.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for looking @jorgefilipecosta! I'm open to any tips or ideas here. I'm pretty new to the components code.

Yeah, we could do away with the BaseControl around each input here with the focal-point-picker. Will have to restyle though to handle the <span>%</span> appended to each.

Might even be worth adding a numericUnit prop in the NumberControl to handle it.

display: inline-block;
font-weight: 500;
height: 30px;
width: 54px;
Copy link
Contributor

Choose a reason for hiding this comment

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

Love the idea of a dedicated NumberControl but nervous about defining the width here. This makes it tougher to use as a full-width control. Maybe there could be a modifier class (.components-number-control__input--narrow or something like that) which applies the width constraint?

@gziolo gziolo added this to the 5.2 (Gutenberg) milestone Feb 13, 2019
@gziolo gziolo added [Feature] UI Components Impacts or related to the UI component system [Type] Task Issues or PRs that have been broken down into an individual action to take labels Feb 13, 2019
@youknowriad
Copy link
Contributor

Noting that the TextComponent supports the type prop which means this new component is somehow a duplicate?

@m-e-h
Copy link
Member Author

m-e-h commented Feb 14, 2019

Whoa. I hadn't even thought of that @youknowriad.

I think there are enough blocks ignoring that and using their own number input that it warrants it's own component. Better to repeat the TextControl once as a new component than to repeat similar code each time a number input is used.

Wondering though if a NumberControl component should just import the TextControl and change the type? Then it's not really a "duplicate", it would just be a more obvious choice for devs that need it.

@chrisvanpatten
Copy link
Contributor

I like the idea of a dedicated NumberControl because it could allow for additional number functionality in the future (perhaps including custom buttons to increment/decrement, or basic validation, or something along those lines), but I agree; it should pull from the TextControl as a base at least until other UI needs become visible.

@m-e-h
Copy link
Member Author

m-e-h commented Feb 14, 2019

One challenge I ran into when trying to use the TextControl for this, is that it's defining onChange in the return rather than in the defautProps.
This makes it readonly for things like the Focal Point Picker that define their own onChange={ this.horizontalPositionChanged }.

It's likely that I'm missing something. Is there a different way I should be doing it?

@youknowriad
Copy link
Contributor

One challenge I ran into when trying to use the TextControl for this, is that it's defining onChange in the return rather than in the defautProps.

That doesn't change anything for me. If the value is not changing, it simply means the value prop is not updated properly for me.

@afercia
Copy link
Contributor

afercia commented Feb 15, 2019

A generic component shouldn't assume an aria-label is always desired. Input fields need to be labelled, In order of preference:

  • a visible label element associated with for/id attributes: in the BaseControl component this is controlled by the presence of both label && id props
  • if there's no id, then the label value is rendered as plain text and the input is supposed to be labelled with an 'aria-label`

Never do both together.

Some controls in the codebase are misleading, for example the FocalPointPicker renders two input fields that are completely unlabelled. The visible text is just text. There's no <label> element or aria-label... going to create an issue.

@m-e-h
Copy link
Member Author

m-e-h commented Feb 20, 2019

I updated this to better handle id and aria-label per @afercia

I'm sticking with wrapping this in it's own BaseControl. Pulling in the TextControl wasn't matching up the for=/id attributes and I struggled to find an elegant way to get at the BaseControl props.

I also added an optional numberUnit prop so a unit of measurement could be added, like the % on the focal-point component.

I also updated the spacer block to see how the NumberControl worked there.

@youknowriad youknowriad removed this from the 5.3 (Gutenberg) milestone Mar 18, 2019
Copy link
Member

@jorgefilipecosta jorgefilipecosta left a comment

Choose a reason for hiding this comment

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

Hi @m-e-h,
Thank you for iterating on this PR.
I did a set of tests, and this PR seems almost ready, I just left some minor suggestions.

Besides the suggestions, I think this PR needs a "New Features" changelog entry in https://github.com/WordPress/gutenberg/blob/master/packages/components/CHANGELOG.md#720-unreleased, and a rebase.

{ ...props }
/>

{ numberUnit && (
Copy link
Member

Choose a reason for hiding this comment

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

Maybe we can update the Number control, to pass children to base control. It would allow us to remove the need for a numbeUnit prop making the component simpler. Current usages would only need to pass span prop with the unit like they do now.

@@ -89,10 +89,9 @@ function RangeControl( {
max={ max }
{ ...props } />
{ afterIcon && <Dashicon icon={ afterIcon } /> }
<input
<NumberControl
Copy link
Member

Choose a reason for hiding this comment

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

Range control is a complex control in itself with validation logic that was recently added. The component already uses a BaseControl so using a NumberControl here would result in a BaseControl nested inside another BaseControl. I would prefer if we did not use NumberControl inside RangeControl at least for now.

numberUnit,
...props
} ) {
const onChangeValue = ( event ) => onChange( Number( event.target.value ) );
Copy link
Member

Choose a reason for hiding this comment

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

Maybe we can change this line to:

	const onChangeValue = ( event ) => onChange(
		event.target.value === '' ? undefined : Number( event.target.value )
	);

The current version causes a bug -- it becomes impossible to have the field empty. It is possible to reproduce the bug testing the spacer.
The bug happens because Number('') === 0;

@jorgefilipecosta jorgefilipecosta added the [Status] Stale Gives the original author opportunity to update before closing. Can be reopened as needed. label Sep 20, 2019
@ZebulanStanphill
Copy link
Member

What is the status of this PR?

@m-e-h
Copy link
Member Author

m-e-h commented Dec 1, 2019

This can probably be closed. The goal here was mostly to clean up the UI style variations across the different number inputs.
There are probably simpler ways to do that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] UI Components Impacts or related to the UI component system [Status] Stale Gives the original author opportunity to update before closing. Can be reopened as needed. [Type] Task Issues or PRs that have been broken down into an individual action to take
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants