PERF: Defer button actions to improve interaction-next-paint (INP) (#28019)
This is a variation on bc3e8a9963cf9a64d114ec751c875025af169690, which was reverted due to issues on iOS. Safari's "in response to user action" check cannot follow the `runAfterFramePaint` chain of interaction -> requestAnimationFrame -> messageChannel, and so some sensitive browser APIs (e.g. clipboard, upload, etc.) were blocked. This commit is similar, but uses `next()` instead of `runAfterFramePaint()`. The result seems the same, but doesn't have the same issue on iOS. The chat-emoji-picker change was required to resolve a test failure. The emoji picker has never closed-on-scroll on desktop, so there is no user-facing change in behavior.
This commit is contained in:
parent
1446596089
commit
dfc947a97d
|
@ -1,6 +1,7 @@
|
|||
import { on } from "@ember/modifier";
|
||||
import { action } from "@ember/object";
|
||||
import { empty, equal, notEmpty } from "@ember/object/computed";
|
||||
import { next } from "@ember/runloop";
|
||||
import { service } from "@ember/service";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import { or } from "truth-helpers";
|
||||
|
@ -118,17 +119,19 @@ export default class DButton extends GlimmerComponentWithDeprecatedParentView {
|
|||
);
|
||||
}
|
||||
} else if (typeof actionVal === "object" && actionVal.value) {
|
||||
if (forwardEvent) {
|
||||
actionVal.value(actionParam, event);
|
||||
} else {
|
||||
actionVal.value(actionParam);
|
||||
}
|
||||
// Using `next()` to optimise INP
|
||||
next(() =>
|
||||
forwardEvent
|
||||
? actionVal.value(actionParam, event)
|
||||
: actionVal.value(actionParam)
|
||||
);
|
||||
} else if (typeof actionVal === "function") {
|
||||
if (forwardEvent) {
|
||||
actionVal(actionParam, event);
|
||||
} else {
|
||||
actionVal(actionParam);
|
||||
}
|
||||
// Using `next()` to optimise INP
|
||||
next(() =>
|
||||
forwardEvent
|
||||
? actionVal(actionParam, event)
|
||||
: actionVal(actionParam)
|
||||
);
|
||||
}
|
||||
} else if (route) {
|
||||
this.router.transitionTo(route);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { alias, match } from "@ember/object/computed";
|
||||
import Mixin from "@ember/object/mixin";
|
||||
import { schedule, throttle } from "@ember/runloop";
|
||||
import { next, schedule, throttle } from "@ember/runloop";
|
||||
import { service } from "@ember/service";
|
||||
import { wantsNewWindow } from "discourse/lib/intercept-click";
|
||||
import { headerOffset } from "discourse/lib/offset-calculator";
|
||||
|
@ -86,9 +86,12 @@ export default Mixin.create({
|
|||
document.querySelector(".card-cloak")?.classList.remove("hidden");
|
||||
|
||||
this.appEvents.trigger("user-card:show", { username });
|
||||
this._positionCard(target, event);
|
||||
this._showCallback(username).then((user) => {
|
||||
this.appEvents.trigger("user-card:after-show", { user });
|
||||
// Using `next()` to optimise INP
|
||||
next(() => {
|
||||
this._positionCard(target, event);
|
||||
this._showCallback(username).then((user) => {
|
||||
this.appEvents.trigger("user-card:after-show", { user });
|
||||
});
|
||||
});
|
||||
|
||||
// We bind scrolling on mobile after cards are shown to hide them if user scrolls
|
||||
|
|
|
@ -13,6 +13,10 @@ export default class ChatChannelMessageEmojiPicker extends Component {
|
|||
context = "chat-channel-message";
|
||||
|
||||
listenToBodyScroll = modifier(() => {
|
||||
if (!this.site.mobileView) {
|
||||
return;
|
||||
}
|
||||
|
||||
const handler = () => {
|
||||
this.chatEmojiPickerManager.close();
|
||||
};
|
||||
|
@ -43,10 +47,6 @@ export default class ChatChannelMessageEmojiPicker extends Component {
|
|||
{
|
||||
placement: "top",
|
||||
modifiers: [
|
||||
{
|
||||
name: "eventListeners",
|
||||
options: { scroll: false, resize: false },
|
||||
},
|
||||
{
|
||||
name: "flip",
|
||||
options: { padding: { top: headerOffset() } },
|
||||
|
|
Loading…
Reference in New Issue