FIX: ensures d-popover closes when clicking on popper (#16675)

I think the no-invalid-interaction is fine here as on click Is not actually used for an expected interaction but as an event bubbling barrier.
This commit is contained in:
Joffrey JAFFEUX 2022-05-09 10:50:29 +02:00 committed by GitHub
parent 4d0ac8636c
commit 131974b3a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 13 deletions

View File

@ -2,6 +2,8 @@ import Component from "@ember/component";
import { iconHTML } from "discourse-common/lib/icon-library"; import { iconHTML } from "discourse-common/lib/icon-library";
import tippy from "tippy.js"; import tippy from "tippy.js";
import { guidFor } from "@ember/object/internals"; import { guidFor } from "@ember/object/internals";
import { action } from "@ember/object";
import { next } from "@ember/runloop";
export default class DiscoursePopover extends Component { export default class DiscoursePopover extends Component {
tagName = ""; tagName = "";
@ -15,13 +17,30 @@ export default class DiscoursePopover extends Component {
didInsertElement() { didInsertElement() {
this._super(...arguments); this._super(...arguments);
this._setupTippy(); this._tippyInstance = this._setupTippy();
}
willDestroyElement() {
this._super(...arguments);
this._tippyInstance?.destroy();
} }
get componentId() { get componentId() {
return guidFor(this); return guidFor(this);
} }
@action
close(event) {
event.preventDefault();
if (!this.isExpanded) {
return;
}
this._tippyInstance?.hide();
}
_setupTippy() { _setupTippy() {
const baseOptions = { const baseOptions = {
trigger: "click", trigger: "click",
@ -30,6 +49,7 @@ export default class DiscoursePopover extends Component {
interactive: true, interactive: true,
allowHTML: false, allowHTML: false,
appendTo: "parent", appendTo: "parent",
hideOnClick: true,
content: content:
this.options?.content || this.options?.content ||
document document
@ -38,20 +58,27 @@ export default class DiscoursePopover extends Component {
":scope > .d-popover-content, :scope > div, :scope > ul" ":scope > .d-popover-content, :scope > div, :scope > ul"
), ),
onShow: () => { onShow: () => {
if (this.isDestroyed || this.isDestroying) { next(() => {
return; if (this.isDestroyed || this.isDestroying) {
} return;
this.set("isExpanded", true); }
this.set("isExpanded", true);
});
return true;
}, },
onHide: () => { onHide: () => {
if (this.isDestroyed || this.isDestroying) { next(() => {
return; if (this.isDestroyed || this.isDestroying) {
} return;
this.set("isExpanded", false); }
this.set("isExpanded", false);
});
return true;
}, },
}; };
tippy( const instance = tippy(
document document
.getElementById(this.componentId) .getElementById(this.componentId)
.querySelector( .querySelector(
@ -59,5 +86,7 @@ export default class DiscoursePopover extends Component {
), ),
Object.assign({}, baseOptions, this.options || {}) Object.assign({}, baseOptions, this.options || {})
); );
return instance?.id ? instance : null;
} }
} }

View File

@ -1,3 +1,4 @@
<div id={{componentId}} class="d-popover {{class}} {{if isExpanded "is-expanded"}}"> {{!-- template-lint-disable no-invalid-interactive --}}
<div {{on "click" (action "close")}} id={{componentId}} class="d-popover {{class}} {{if isExpanded "is-expanded"}}">
{{yield (hash isExpanded=isExpanded)}} {{yield (hash isExpanded=isExpanded)}}
</div> </div>

View File

@ -39,16 +39,20 @@ discourseModule("Integration | Component | d-popover", function (hooks) {
}); });
componentTest("show/hide popover from component", { componentTest("show/hide popover from component", {
template: hbs`{{#d-popover}}{{d-button icon="chevron-down"}}<ul><li class="test">foo</li></ul>{{/d-popover}}`, template: hbs`{{#d-popover}}{{d-button class="trigger" icon="chevron-down"}}<ul><li class="test">foo</li><li>{{d-button icon="times" class="closer"}}</li></ul>{{/d-popover}}`,
async test(assert) { async test(assert) {
assert.notOk(exists(".d-popover.is-expanded")); assert.notOk(exists(".d-popover.is-expanded"));
assert.notOk(exists(".test")); assert.notOk(exists(".test"));
await click(".btn"); await click(".trigger");
assert.ok(exists(".d-popover.is-expanded")); assert.ok(exists(".d-popover.is-expanded"));
assert.equal(query(".test").innerText.trim(), "foo"); assert.equal(query(".test").innerText.trim(), "foo");
await click(".closer");
assert.notOk(exists(".d-popover.is-expanded"));
}, },
}); });