Skip to content

Commit 44e78a9

Browse files
authored
[Interactive Graph Editor] Stop cursor jumps in number input fields (#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
1 parent 01edfb8 commit 44e78a9

File tree

4 files changed

+85
-5
lines changed

4 files changed

+85
-5
lines changed

.changeset/neat-kiwis-relax.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@khanacademy/perseus-editor": patch
3+
---
4+
5+
[Interactive Graph Editor] Stop cursor jumps in number input fields

packages/perseus-editor/src/components/__tests__/scrollless-number-text-field.test.tsx

+41
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,45 @@ describe("ScrolllessNumberTextField", () => {
5353
// Assert
5454
expect(onChange).not.toHaveBeenCalled();
5555
});
56+
57+
test("calls onFocus on focus", async () => {
58+
// Arrange
59+
const onFocus = jest.fn();
60+
render(
61+
<ScrolllessNumberTextField
62+
value="42"
63+
onChange={() => {}}
64+
onFocus={onFocus}
65+
/>,
66+
);
67+
68+
// Act
69+
// Tab to focus on input
70+
await userEvent.tab();
71+
72+
// Assert
73+
expect(onFocus).toHaveBeenCalled();
74+
});
75+
76+
test("calls onBlur on blur", async () => {
77+
// Arrange
78+
const onBlur = jest.fn();
79+
render(
80+
<ScrolllessNumberTextField
81+
value="42"
82+
onChange={() => {}}
83+
onBlur={onBlur}
84+
/>,
85+
);
86+
87+
// Tab to focus on input
88+
await userEvent.tab();
89+
90+
// Act
91+
// Tab to move focus away
92+
await userEvent.tab();
93+
94+
// Assert
95+
expect(onBlur).toHaveBeenCalled();
96+
});
5697
});

packages/perseus-editor/src/components/scrollless-number-text-field.tsx

+37-5
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,14 @@ import type {PropsFor} from "@khanacademy/wonder-blocks-core";
66
/**
77
* This is a custom text field of type="number" for use in Perseus Editors.
88
*
9-
* This makes it so that the text field's input number updates on scroll
10-
* without scrolling the page.
9+
* This component makes it so that
10+
* 1. the text field's input number updates on scroll without
11+
* scrolling the page.
12+
* 2. the input is controlled as long as it does not have focus.
13+
* While it is focused, it becomes editable and emits onChange
14+
* events. This is useful to make sure that input behavior
15+
* remains predictable, rather than possibly having the cursor
16+
* jump around uenxpectedly.
1117
*
1218
* NOTE 1: Native HTML number inputs do not update the number value on scroll,
1319
* they only scroll the page. Inputs in React do NOT work this way (explanation
@@ -16,10 +22,14 @@ import type {PropsFor} from "@khanacademy/wonder-blocks-core";
1622
* the page to scroll. The behavior in this component is an improvement on
1723
* the React behavior, but it's the opposite of the native HTML behavior.
1824
*
19-
* NOTE 2: Firefox seems to have a custom override for this. Even with this
20-
* stopPropogation, Firefox matches the native HTML behavior.
25+
* NOTE 2: Firefox seems to have a custom override for input scroll. Even
26+
* with this stopPropogation, Firefox matches the native HTML behavior.
2127
*/
2228
const ScrolllessNumberTextField = (props: PropsFor<typeof TextField>) => {
29+
const {value, onChange, ...restOfProps} = props;
30+
const [focused, setFocused] = React.useState(false);
31+
const [wipValue, setWipValue] = React.useState("");
32+
2333
const inputRef = React.useRef<HTMLInputElement>(null);
2434

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

42-
return <TextField type="number" {...props} ref={inputRef} />;
52+
return (
53+
<TextField
54+
{...restOfProps}
55+
type="number"
56+
value={focused ? wipValue : value}
57+
onChange={(newValue) => {
58+
setWipValue(newValue);
59+
onChange(newValue);
60+
}}
61+
onFocus={(e) => {
62+
setWipValue(value);
63+
setFocused(true);
64+
65+
props.onFocus?.(e);
66+
}}
67+
onBlur={(e) => {
68+
setFocused(false);
69+
70+
props.onBlur?.(e);
71+
}}
72+
ref={inputRef}
73+
/>
74+
);
4375
};
4476

4577
export default ScrolllessNumberTextField;

packages/perseus-editor/src/widgets/interactive-graph-editor/locked-figures/locked-point-settings.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ const LockedPointSettings = (props: Props) => {
9898
onRemove,
9999
// defining point props
100100
showPoint,
101+
error,
101102
expanded,
102103
onTogglePoint,
103104
onToggle,
@@ -210,6 +211,7 @@ const LockedPointSettings = (props: Props) => {
210211
coord={coord}
211212
style={styles.spaceUnder}
212213
onChange={handleCoordChange}
214+
error={!!error}
213215
/>
214216

215217
{/* Toggle switch */}

0 commit comments

Comments
 (0)