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

fix(@clayui/color-picker): Update hue slider to use html range input #5156

Closed
wants to merge 12 commits into from

Conversation

pat270
Copy link
Member

@pat270 pat270 commented Oct 24, 2022

fixes #5137

I finally got this working with the range input. I used the onKeyUp and onPointerUp events to update the Color Picker. The only problem with this is the map's hue doesn't update while dragging the thumb. Since I have something working, I can probably get it to work with onChange only, just need to throttle or debounce the updates so it doesn't lag so much.

In 87331f6#diff-47b43a95fa966e5189545f95207e5d85c86bb0a2ac02963ec706530728d79af5R39-R41, I had to blur then re-focus the input because FF has a range input issue when using onPointerUp. It fails to update the input value for some reason. This problem doesn't exist when using onMouseUp.

@pat270 pat270 force-pushed the clay-5137 branch 3 times, most recently from fef1014 to 5445aef Compare October 25, 2022 19:28
Copy link
Member

@matuzalemsteles matuzalemsteles left a comment

Choose a reason for hiding this comment

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

Hey @pat270 there are some things we need to think about before going ahead with this and maybe improve some things, more in relation to the implementation of React.

It also seems that we have some problems with Slider as you said, I had made some changes to try to understand but it seems that React has some problems with input range, I will continue researching more about this but maybe we will have to not use the input range but we can still make it accessible.

I'll leave some comments here about the improvements that can be made.


const removeListeners = () => {
selectorActive.current = false;
const [internalValue, setInternalValue] = useState<number>(value);
Copy link
Member

Choose a reason for hiding this comment

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

We don't need another state here, because we also have a state in the parent component, in which case we have access to them which are value and onChange it is easier to maintain a source of truth than to have multiple states and keep synchronizing them all, this is also bad because of unnecessary rerenders.


const {onPointerMove, setXY, x, y} = usePointerPosition(containerRef);
const {setXY, y} = usePointerPosition(containerRef);
Copy link
Member

Choose a reason for hiding this comment

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

We don't need this hook anymore and we don't need to set setXY anymore because we are no longer using them here. It used to be just used to get x information to deal with the position of the pointer, as we don't have it anymore, we don't need it anymore.

Comment on lines 38 to 33
event.target.blur();

event.target.focus();
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand very well why we need this 😅, could you explain it better?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think there is a bug in FF input range with onPointerUp. It keeps dragging the slider thumb even when the left mouse button is released. This didn't happen when I used onMouseUp. The only way I could get it to work properly was blur then focus.

Copy link
Member

Choose a reason for hiding this comment

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

Hmm this is weird, I'll do some testing.

Comment on lines 43 to +37
React.useEffect(() => {
if (containerRef.current) {
setXY({x: hueToX(value, containerRef.current), y});
}
setInternalValue(value);
Copy link
Member

Choose a reason for hiding this comment

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

As we are going to use the parent state value and onChange we no longer need this to synchronize the values.

Copy link
Member Author

Choose a reason for hiding this comment

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

I couldn't do this one due to #5156 (comment).

Comment on lines 197 to 226
<ClayInput.Group>
<ClayInput.GroupItem>
<ClayInput
data-testid="hInput"
insetBefore
max="360"
min="0"
onChange={(event) => {
const value = event.target.value;

let newVal = Number(value);

if (newVal < 0) {
newVal = 0;
} else if (newVal > 360) {
newVal = 360;
}

onHueChange(Math.round(newVal));

onColorChange(tinycolor({h: newVal, s, v}));
}}
type="number"
value={hue}
/>
<ClayInput.GroupInsetItem before tag="label">
H
</ClayInput.GroupInsetItem>
</ClayInput.GroupItem>
</ClayInput.Group>
Copy link
Member

Choose a reason for hiding this comment

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

As we are dealing with internal components we can move this composition to the Hue component, it is easier to keep the responsibility organized. As it is not an internal component, there is no problem rendering the bar along with the input.

window.removeEventListener('pointermove', onPointerMove);
window.removeEventListener('pointerup', removeListeners);
};
const handleOnChangeEnd = (event: any) => {
Copy link
Member

Choose a reason for hiding this comment

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

Since we won't have the internal state anymore, just add the onChange callback as a property of the ClaySlider, we won't need that anymore because we will be directly updating the parent state instead of the internal one.

@pat270
Copy link
Member Author

pat270 commented Oct 28, 2022

@matuzalemsteles Thanks for the input, I'll update this pr with your suggestions.

The problem is with the onChange, onHueChange, etc functions. React ends up re-rendering the slider when the value changes and the mouse loses focus. I was thinking if we could run onHueChange in all the other components, but not in slider. It would work.

@matuzalemsteles
Copy link
Member

The problem is with the onChange, onHueChange, etc functions. React ends up re-rendering the slider when the value changes and the mouse loses focus. I was thinking if we could run onHueChange in all the other components, but not in slider. It would work.

I see, I'm not sure if that would be the problem because internally the ClaySlider has the useInternalState state, so if changing the slider value it causes a re-render, we wouldn't be doing anything different, other than controlling the state would stay in the ColorPicker instead of the slider when we are using the value and onChange properties.

I had made some changes to just use Hue's onChange, but the behavior is very strange that it loses the "focus" of the range when the mouse goes outside the bar, this is strange because the focus is still in the range if you monitor the document.activeElement, it doesn't make much sense.

Screen.Recording.2022-10-28.at.12.16.15.PM.mov

@pat270
Copy link
Member Author

pat270 commented Oct 28, 2022

The recording was exactly what was happening to me. useState seems to make this a non issue. It's the way the onChange functions work in the Editor imo. I'm trying useState with the alpha slider. I'll send a pr once I get swatches updating and we can compare.

@matuzalemsteles
Copy link
Member

@pat270 I think the most ideal thing here to go with this would be to use onChange to update the Hue state so we can see the editor update as the slider changes its value. I'm trying to investigate why the mouse is getting lost when trying to move the slider.

@matuzalemsteles
Copy link
Member

Hey @pat270 I think we're going to have to refactor how we implement the ClaySlider to behave differently and that the mouse moves work correctly when the onChange changes, maybe the input[type=range] maybe it has to be just the thumb and we will have to control movement via JS so it doesn't bug when state update happens.

@pat270 pat270 closed this May 4, 2023
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.

Color Picker use input type range
2 participants