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

View File

@ -39,16 +39,20 @@ discourseModule("Integration | Component | d-popover", function (hooks) {
});
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) {
assert.notOk(exists(".d-popover.is-expanded"));
assert.notOk(exists(".test"));
await click(".btn");
await click(".trigger");
assert.ok(exists(".d-popover.is-expanded"));
assert.equal(query(".test").innerText.trim(), "foo");
await click(".closer");
assert.notOk(exists(".d-popover.is-expanded"));
},
});