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

Improve NumericInput and AbstractButton internals #4201

Merged
merged 6 commits into from
Jul 7, 2020
Merged

Improve NumericInput and AbstractButton internals #4201

merged 6 commits into from
Jul 7, 2020

Conversation

ejose19
Copy link
Contributor

@ejose19 ejose19 commented Jun 30, 2020

Fixes #4200

Checklist

  • Includes tests
  • Update documentation (No changes to docs)

Changes proposed in this pull request:

  • Add a check to each iteration of handleContinuousChange, since mouseup event won't fire if the mouse is released on the disabled element (after it reached min/max limit) current behaviour keeps running it indefinitely when using min/max props and releasing the mouseup after described event. Fixed using AnchorButton

  • Allow accessing class instance during onValueChange callback, this is necessary as if doing any conditional logic to allow a value, one needs to update the internal value to keep it in sync with given value prop (see my comment on this issue for more details) Removed, another PR improves controlled mode

  • Add componentDidUpdate getDerivedStateFromProps to AbstractButton, related to the 1st issue, its handleKeyUp is never fired if the button is disabled, so internal state is still "active" while the button is disabled (which is not correct) displaying inconsistent UI to the user when using along other components (For example NumericInput)

Reviewers should focus on:

Mentioned changes

Screenshot

N/A

@palantirtech
Copy link
Member

Thanks for your interest in palantir/blueprint, @ejose19! Before we can accept your pull request, you need to sign our contributor license agreement - just visit https://cla.palantir.com/ and follow the instructions. Once you sign, I'll automatically update this pull request.

@ejose19 ejose19 changed the title Improve NumericInput internals Improve NumericInput and AbstractButton internals Jun 30, 2020
@adidahiya adidahiya self-requested a review June 30, 2020 20:11
Copy link
Contributor

@adidahiya adidahiya left a comment

Choose a reason for hiding this comment

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

Allow accessing class instance during onValueChange callback, this is necessary as if doing any conditional logic to allow a value, one needs to update the internal value to keep it in sync with given value prop

I'm not yet convinced that this is necessary. What kind of conditional logic are you doing? Can we support that use case some other way instead of providing access to the component's internals? I don't want to increase the size of the public API this way.


Also, I think this whole issue might be easier solved by simply replacing the Button components rendered by NumericInput with AnchorButton components... they are able to receive events when disabled=true

packages/core/src/components/button/abstractButton.tsx Outdated Show resolved Hide resolved
// this situation can happen (NumericInput buttons), hence the need
// to check if disabled prop has been passed and change isActive
// accordingly
public componentDidUpdate() {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should be implemented inside static getDerivedStateFromProps instead:

    protected static getDerivedStateFromProps(props: IButtonProps, state: IButtonState) {
        if (state.isActive && props.disabled) {
            return {
                isActive: false,
            };
        }

        return null;
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If this is better than componentDidUpdate then no issues, I will change it.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's better because it's a more natural place to manage state updates, it gets called before render. Check out the React lifecycle documentation to see what kinds of behavior is recommended in the various methods

@ejose19
Copy link
Contributor Author

ejose19 commented Jul 7, 2020

@adidahiya Regarding the instance access, if there's any other way then great, but I would like to know how you would do that. Here's the issue: Controlled mode, my value is set to 1, and NumericInput sets its internal state to '1', now I only want integers in a range, so I add a conditional logic to onValueChange callback to apply the new value to my state, this theorically works good if the user is either using the buttons or tapping only numbers, but there are 2 cases: (pressing the letter 'e' is allowed, and pasting content into the field) first action is allowed and internal value is stored as '1e' but my state rejected it and it's 1, now they're not in sync and buttons won't display limits properly. On paste if text pasted is invalid (letters only), then internal state is VALUE_EMPTY and my state is still 1. So either we need to add a callback function like ("isValid") to determine if internal state should change, or as I'm doing in this patch, let me change the internal state manually after I do my checks.

Copy link
Contributor Author

@ejose19 ejose19 left a comment

Choose a reason for hiding this comment

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

Applied both recommendations and I confirm they work (Using AnchorButton on numericInput and getDerivedStateFromProps on abstractButton)

// this situation can happen (NumericInput buttons), hence the need
// to check if disabled prop has been passed and change isActive
// accordingly
public componentDidUpdate() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If this is better than componentDidUpdate then no issues, I will change it.

@adidahiya
Copy link
Contributor

@ejose19 regarding controlled mode... check out the PR I just opened #4211... that should get you sorted. For this PR please just stick to fixing #4200. I'll merge my PR today and then you can test it.

@adidahiya
Copy link
Contributor

thanks for testing my branch. I'll merge yours first so you don't have to deal with conflicts

@adidahiya adidahiya merged commit 9b215c1 into palantir:develop Jul 7, 2020
@ejose19 ejose19 deleted the ej/improve-numeric-input branch July 7, 2020 21:38
@ejose19
Copy link
Contributor Author

ejose19 commented Sep 8, 2020

@adidahiya Since there's a side effect caused by using AnchorButton, should we use the original idea instead?

Add a check to each iteration of handleContinuousChange, since mouseup event won't fire if the mouse is released on the disabled element (after it reached min/max limit) current behaviour keeps running it indefinitely when using min/max props and releasing the mouseup after described event.

@adidahiya
Copy link
Contributor

@ejose19 ok, yeah, I would be open to a change that switches to the original idea using Button instead

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

NumericInput events run incorrectly when using min or max props
3 participants