Skip to content

Commit 60dce78

Browse files
authored
Merge pull request #2927 from rodasarede/new_bug_pic_fix
Fix unexpected behaviour of the cursor
2 parents 910a3cb + 4e04729 commit 60dce78

File tree

2 files changed

+86
-9
lines changed

2 files changed

+86
-9
lines changed

components/dash-core-components/src/components/Input.react.js

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -182,16 +182,23 @@ export default class Input extends PureComponent {
182182

183183
onChange() {
184184
const {debounce} = this.props;
185-
if (debounce) {
186-
if (Number.isFinite(debounce)) {
187-
this.debounceEvent(debounce);
185+
const input = this.input.current;
186+
const cursorPosition = input.selectionStart;
187+
const currentValue = input.value;
188+
this.setState({value: currentValue}, () => {
189+
if (debounce) {
190+
if (Number.isFinite(debounce)) {
191+
this.debounceEvent(debounce);
192+
}
193+
if (this.props.type !== 'number') {
194+
setTimeout(() => {
195+
input.setSelectionRange(cursorPosition, cursorPosition);
196+
}, 0);
197+
}
198+
} else {
199+
this.onEvent();
188200
}
189-
if (this.props.type !== 'number') {
190-
this.setState({value: this.input.current.value});
191-
}
192-
} else {
193-
this.onEvent();
194-
}
201+
});
195202
}
196203
}
197204

components/dash-core-components/tests/integration/input/test_input_basics.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,73 @@ def test_inbs003_styles_are_scoped(dash_dcc):
103103
dash_outline_css = dash_input.value_of_css_property("outline")
104104

105105
assert external_outline_css != dash_outline_css
106+
107+
108+
@pytest.mark.parametrize(
109+
"initial_text, invalid_char, cursor_position_before, expected_text, expected_cursor_position",
110+
[
111+
("abcdddef", "/", 2, "ab/cdddef", 3),
112+
("abcdef", "$", 2, "ab$cdef", 3),
113+
("abcdef", "$", 3, "abc$def", 4),
114+
("abcdef", "A", 4, "abcdAef", 5), # valid character
115+
],
116+
)
117+
def test_inbs004_cursor_position_on_invalid_input(
118+
dash_dcc,
119+
initial_text,
120+
invalid_char,
121+
cursor_position_before,
122+
expected_text,
123+
expected_cursor_position,
124+
):
125+
app = Dash(__name__)
126+
127+
app.layout = html.Div(
128+
[
129+
dcc.Input(
130+
id="test-input",
131+
type="text",
132+
placeholder="File name",
133+
className="create_file_input",
134+
pattern="[a-zA-Z_][a-zA-Z0-9_]*",
135+
),
136+
html.Div(id="output"),
137+
]
138+
)
139+
140+
dash_dcc.start_server(app)
141+
input_elem = dash_dcc.find_element("#test-input")
142+
143+
input_elem.send_keys(initial_text)
144+
assert (
145+
input_elem.get_attribute("value") == initial_text
146+
), "Initial text should match"
147+
148+
dash_dcc.driver.execute_script(
149+
f"""
150+
var elem = arguments[0];
151+
elem.setSelectionRange({cursor_position_before}, {cursor_position_before});
152+
elem.focus();
153+
""",
154+
input_elem,
155+
)
156+
157+
input_elem.send_keys(invalid_char)
158+
159+
assert (
160+
input_elem.get_attribute("value") == expected_text
161+
), f"Input should be {expected_text}"
162+
163+
cursor_position = dash_dcc.driver.execute_script(
164+
"""
165+
var elem = arguments[0];
166+
return elem.selectionStart;
167+
""",
168+
input_elem,
169+
)
170+
171+
assert (
172+
cursor_position == expected_cursor_position
173+
), f"Cursor should be at position {expected_cursor_position}"
174+
175+
assert dash_dcc.get_logs() == []

0 commit comments

Comments
 (0)