Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit efcff5f

Browse files
committedMar 21, 2025
Debounce arrow up/down on BuilderNumberInput
1 parent c08549b commit efcff5f

File tree

3 files changed

+48
-8
lines changed

3 files changed

+48
-8
lines changed
 

‎addons/html_builder/static/src/core/building_blocks/builder_number_input.js

+14-8
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import {
1010
BuilderTextInputBase,
1111
textInputBasePassthroughProps,
1212
} from "@html_builder/core/building_blocks/builder_text_input_base";
13+
import { useChildRef } from "@web/core/utils/hooks";
1314
import { pick } from "@web/core/utils/objects";
15+
import { useDebounced } from "@web/core/utils/timing";
1416

1517
export class BuilderNumberInput extends Component {
1618
static template = "html_builder.BuilderNumberInput";
@@ -46,6 +48,16 @@ export class BuilderNumberInput extends Component {
4648
this.commit = commit;
4749
this.preview = preview;
4850
this.state = state;
51+
52+
this.inputRef = useChildRef();
53+
this.debouncedCommitValue = useDebounced(() => {
54+
const normalizedDisplayValue = this.commit(this.inputRef.el.value);
55+
this.inputRef.el.value = normalizedDisplayValue;
56+
}, 550);
57+
// ↑ 500 is the delay when holding keydown between the 1st and 2nd event
58+
// fired. Some additional delay by the browser may add another ~5-10ms.
59+
// We debounce above that threshold to keep a single history step when
60+
// holding up/down on a number input.
4961
}
5062

5163
/**
@@ -130,16 +142,10 @@ export class BuilderNumberInput extends Component {
130142
});
131143
}
132144

133-
onChange(e) {
134-
const normalizedDisplayValue = this.commit(e.target.value);
135-
e.target.value = normalizedDisplayValue;
136-
}
137-
138145
get displayValue() {
139146
return this.formatRawValue(this.state.value);
140147
}
141148

142-
// TODO: use this.preview or this.commit?
143149
onKeydown(e) {
144150
if (!["ArrowUp", "ArrowDown"].includes(e.key)) {
145151
return;
@@ -155,8 +161,8 @@ export class BuilderNumberInput extends Component {
155161
});
156162
}
157163
e.target.value = values.join(" ");
158-
// OK because it only uses event.target.value.
159-
this.onChange(e);
164+
this.preview(e.target.value);
165+
this.debouncedCommitValue();
160166
}
161167

162168
get textInputBaseProps() {

‎addons/html_builder/static/src/core/building_blocks/builder_number_input.xml

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<BuilderComponent>
66
<BuilderTextInputBase
77
t-props="textInputBaseProps"
8+
inputRef="inputRef"
89
value="displayValue"
910
inputClasses="props.inputClasses ? `text-end ${props.inputClasses}` : 'text-end'"
1011
commit="commit"

‎addons/html_builder/static/tests/custom_tab/builder_components/builder_number_input.test.js

+33
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,39 @@ describe("keyboard triggers", () => {
385385
expect("[data-action-id='customAction'] input").toHaveValue("-1");
386386
expect(":iframe .test-options-target").toHaveAttribute("data-number", "-1");
387387
});
388+
test("apply preview on keydown and debounce commit operation", async () => {
389+
addActionOption({
390+
customAction: {
391+
getValue: ({ editingElement }) => editingElement.innerHTML,
392+
apply: ({ editingElement, value }) => {
393+
expect.step(`customAction ${value}`);
394+
editingElement.innerHTML = value;
395+
},
396+
},
397+
});
398+
addOption({
399+
selector: ".test-options-target",
400+
template: xml`<BuilderNumberInput action="'customAction'"/>`,
401+
});
402+
await setupWebsiteBuilder(`
403+
<div class="test-options-target">10</div>
404+
`);
405+
await contains(":iframe .test-options-target").click();
406+
await contains(".options-container input").focus();
407+
// Simulate a single keydown hold down for a while.
408+
await contains(".options-container input").keyDown("ArrowUp");
409+
await advanceTime(500); // Default browser delay between 1st & 2nd keydown.
410+
await contains(".options-container input").keyDown("ArrowUp");
411+
await advanceTime();
412+
await contains(".options-container input").keyDown("ArrowUp");
413+
await advanceTime();
414+
expect(":iframe .test-options-target").toHaveInnerHTML("13");
415+
// 3 previews
416+
expect.verifySteps(["customAction 11", "customAction 12", "customAction 13"]);
417+
await advanceTime(560); // Debounce = 550
418+
// 1 commit
419+
expect.verifySteps(["customAction 13"]);
420+
});
388421
});
389422
describe("unit & saveUnit", () => {
390423
test("should handle unit", async () => {

0 commit comments

Comments
 (0)
Please sign in to comment.