DEV: Refactor user-tip to avoid unneeded wrapper element (#29365)

We were using a modifier purely for its lifecycle hooks - not to modify an element. This commit switches to using a helper, which provides a similar lifecycle, but without needing to be attached to an element.
This commit is contained in:
David Taylor 2024-10-23 13:36:04 +01:00 committed by GitHub
parent adef7081a2
commit c6c09db5b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 58 additions and 8 deletions

View File

@ -4,6 +4,7 @@ import { schedule } from "@ember/runloop";
import { service } from "@ember/service";
import { modifier } from "ember-modifier";
import UserTipContainer from "discourse/components/user-tip-container";
import helperFn from "discourse/helpers/helper-fn";
import escape from "discourse-common/lib/escape";
import { iconHTML } from "discourse-common/lib/icon-library";
import I18n from "discourse-i18n";
@ -14,7 +15,7 @@ export default class UserTip extends Component {
@service userTips;
@service tooltip;
registerTip = modifier(() => {
registerTip = helperFn((_, on) => {
const tip = {
id: this.args.id,
priority: this.args.priority ?? 0,
@ -22,9 +23,9 @@ export default class UserTip extends Component {
this.userTips.addAvailableTip(tip);
return () => {
on.cleanup(() => {
this.userTips.removeAvailableTip(tip);
};
});
});
tip = modifier((element) => {
@ -82,10 +83,9 @@ export default class UserTip extends Component {
}
<template>
<div {{this.registerTip}}>
{{#if this.shouldRenderTip}}
<span {{this.tip}}></span>
{{/if}}
</div>
{{this.registerTip}}
{{#if this.shouldRenderTip}}
<span {{this.tip}}></span>
{{/if}}
</template>
}

View File

@ -0,0 +1,50 @@
import Helper from "@ember/component/helper";
import { registerDestructor } from "@ember/destroyable";
import { bind } from "discourse-common/utils/decorators";
/**
* Build an Ember helper with cleanup logic. The passed function will be called with the named argument,
* and an 'on' utility object which allows you to register a cleanup function via `on.cleanup(...)`.
*
* Whenever any autotracked state is changed, the cleanup function will be run, and your function
* will be re-evaluated.
*
* @param {(args: object, on: { cleanup: () => void } ) => any} fn - The helper function.
*/
export default function helperFn(callback) {
return class extends Helper {
cleanupFn = null;
constructor() {
super(...arguments);
registerDestructor(this, this.cleanup);
}
compute(positional, named) {
if (positional.length) {
throw new Error(
"Positional arguments are not permitted for helperFn-defined helpers. Use named arguments instead."
);
}
this.cleanup();
const on = {
cleanup: (fn) => {
if (this.cleanupFn) {
throw new Error("on.cleanup can only be called once");
}
this.cleanupFn = fn;
},
};
return callback(named, on);
}
@bind
cleanup() {
this.cleanupFn?.();
this.cleanupFn = null;
}
};
}