Skip to content

Commit

Permalink
[Interactive Graph Editor] Stop cursor jumps in number input fields (#…
Browse files Browse the repository at this point in the history
…1912)

## Summary:

In order to stop cursor jumps in number fields, up I'm updating the ScrolllessNumberTextField
component to have part of the implementation of EditableControlledInput, which makes sure that
the input stays consistent until blurred.

Issue: https://khanacademy.atlassian.net/browse/LEMS-2303

## Test plan:
- Go to http://localhost:6006/?path=/story/perseuseditor-widgets-interactive-graph--interactive-graph-segments
- Scroll down to the start coords for the segments
- Clear an input and type in ".5"
- Confirm that it does NOT auto-update to 0.5 immediately
- Confirm that it auto-updates to 0.5 after moving focus off the input
- Type in "1.5"
- Move the cursor right before the "."
- Press backspace
- Confirm that the cursor does not jump

## Before and after demos

Before

https://github.com/user-attachments/assets/66c0e69d-ed12-45a7-9527-26854a676ae7

After

https://github.com/user-attachments/assets/a1e396cf-7b62-43d4-8e00-006b78e6c69a

Author: nishasy

Reviewers: benchristel, catandthemachines, anakaren-rojas

Required Reviewers:

Approved By: benchristel

Checks: ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x), ✅ Publish npm snapshot (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ Check builds for changes in size (ubuntu-latest, 20.x), ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ gerald

Pull Request URL: #1912
  • Loading branch information
nishasy authored Nov 26, 2024
1 parent 01edfb8 commit 44e78a9
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/neat-kiwis-relax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@khanacademy/perseus-editor": patch
---

[Interactive Graph Editor] Stop cursor jumps in number input fields
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,45 @@ describe("ScrolllessNumberTextField", () => {
// Assert
expect(onChange).not.toHaveBeenCalled();
});

test("calls onFocus on focus", async () => {
// Arrange
const onFocus = jest.fn();
render(
<ScrolllessNumberTextField
value="42"
onChange={() => {}}
onFocus={onFocus}
/>,
);

// Act
// Tab to focus on input
await userEvent.tab();

// Assert
expect(onFocus).toHaveBeenCalled();
});

test("calls onBlur on blur", async () => {
// Arrange
const onBlur = jest.fn();
render(
<ScrolllessNumberTextField
value="42"
onChange={() => {}}
onBlur={onBlur}
/>,
);

// Tab to focus on input
await userEvent.tab();

// Act
// Tab to move focus away
await userEvent.tab();

// Assert
expect(onBlur).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ import type {PropsFor} from "@khanacademy/wonder-blocks-core";
/**
* This is a custom text field of type="number" for use in Perseus Editors.
*
* This makes it so that the text field's input number updates on scroll
* without scrolling the page.
* This component makes it so that
* 1. the text field's input number updates on scroll without
* scrolling the page.
* 2. the input is controlled as long as it does not have focus.
* While it is focused, it becomes editable and emits onChange
* events. This is useful to make sure that input behavior
* remains predictable, rather than possibly having the cursor
* jump around uenxpectedly.
*
* NOTE 1: Native HTML number inputs do not update the number value on scroll,
* they only scroll the page. Inputs in React do NOT work this way (explanation
Expand All @@ -16,10 +22,14 @@ import type {PropsFor} from "@khanacademy/wonder-blocks-core";
* the page to scroll. The behavior in this component is an improvement on
* the React behavior, but it's the opposite of the native HTML behavior.
*
* NOTE 2: Firefox seems to have a custom override for this. Even with this
* stopPropogation, Firefox matches the native HTML behavior.
* NOTE 2: Firefox seems to have a custom override for input scroll. Even
* with this stopPropogation, Firefox matches the native HTML behavior.
*/
const ScrolllessNumberTextField = (props: PropsFor<typeof TextField>) => {
const {value, onChange, ...restOfProps} = props;
const [focused, setFocused] = React.useState(false);
const [wipValue, setWipValue] = React.useState("");

const inputRef = React.useRef<HTMLInputElement>(null);

React.useEffect(() => {
Expand All @@ -39,7 +49,29 @@ const ScrolllessNumberTextField = (props: PropsFor<typeof TextField>) => {
};
}, [inputRef]);

return <TextField type="number" {...props} ref={inputRef} />;
return (
<TextField
{...restOfProps}
type="number"
value={focused ? wipValue : value}
onChange={(newValue) => {
setWipValue(newValue);
onChange(newValue);
}}
onFocus={(e) => {
setWipValue(value);
setFocused(true);

props.onFocus?.(e);
}}
onBlur={(e) => {
setFocused(false);

props.onBlur?.(e);
}}
ref={inputRef}
/>
);
};

export default ScrolllessNumberTextField;
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ const LockedPointSettings = (props: Props) => {
onRemove,
// defining point props
showPoint,
error,
expanded,
onTogglePoint,
onToggle,
Expand Down Expand Up @@ -210,6 +211,7 @@ const LockedPointSettings = (props: Props) => {
coord={coord}
style={styles.spaceUnder}
onChange={handleCoordChange}
error={!!error}
/>

{/* Toggle switch */}
Expand Down

0 comments on commit 44e78a9

Please sign in to comment.