mirror of
https://github.com/discourse/discourse.git
synced 2024-12-02 11:13:38 +08:00
fe16633a0c
menus and tooltips are now appended to their own portals. The service are the only responsible for managing the instances, prior to this commit, services could manage one instance, but the DMenu and DTooltip components could also take over which could cause unexpected states. This change also allows nested menus/tooltips. Other notable changes: - few months ago core copied the CloseOnClickOutside modifier of float-kit without removing the float-kit one, this commit now only use the core one. - the close function is now trully async - the close function accepts an instance or an identifier as parameter
118 lines
2.6 KiB
JavaScript
118 lines
2.6 KiB
JavaScript
import { tracked } from "@glimmer/tracking";
|
|
import { getOwner, setOwner } from "@ember/application";
|
|
import { action } from "@ember/object";
|
|
import { guidFor } from "@ember/object/internals";
|
|
import { service } from "@ember/service";
|
|
import { MENU } from "float-kit/lib/constants";
|
|
import FloatKitInstance from "float-kit/lib/float-kit-instance";
|
|
|
|
export default class DMenuInstance extends FloatKitInstance {
|
|
@service menu;
|
|
@service site;
|
|
@service modal;
|
|
|
|
/**
|
|
* Indicates whether the menu is expanded or not.
|
|
* @property {boolean} expanded - Tracks the state of menu expansion, initially set to false.
|
|
*/
|
|
@tracked expanded = false;
|
|
|
|
/**
|
|
* Specifies whether the trigger for opening/closing the menu is detached from the menu itself.
|
|
* This is the case when a menu is trigger programmaticaly instead of through the <DMenu /> component.
|
|
* @property {boolean} detachedTrigger - Tracks whether the trigger is detached, initially set to false.
|
|
*/
|
|
@tracked detachedTrigger = false;
|
|
|
|
/**
|
|
* Configuration options for the DMenuInstance.
|
|
* @property {Object} options - Options object that configures the menu behavior and display.
|
|
*/
|
|
@tracked options;
|
|
|
|
@tracked _trigger;
|
|
|
|
constructor(owner, options = {}) {
|
|
super(...arguments);
|
|
|
|
setOwner(this, owner);
|
|
this.options = { ...MENU.options, ...options };
|
|
}
|
|
|
|
get portalOutletElement() {
|
|
return document.getElementById("d-menu-portals");
|
|
}
|
|
|
|
get trigger() {
|
|
return this._trigger;
|
|
}
|
|
|
|
set trigger(element) {
|
|
this._trigger = element;
|
|
this.id = element.id || guidFor(element);
|
|
this.setupListeners();
|
|
}
|
|
|
|
@action
|
|
async close() {
|
|
if (getOwner(this).isDestroying) {
|
|
return;
|
|
}
|
|
|
|
await super.close(...arguments);
|
|
|
|
if (this.site.mobileView && this.options.modalForMobile) {
|
|
await this.modal.close();
|
|
}
|
|
|
|
await this.menu.close(this);
|
|
}
|
|
|
|
@action
|
|
async show() {
|
|
await super.show(...arguments);
|
|
await this.menu.show(this);
|
|
}
|
|
|
|
@action
|
|
async onMouseMove(event) {
|
|
if (this.expanded && this.trigger.contains(event.target)) {
|
|
return;
|
|
}
|
|
|
|
await this.onTrigger(event);
|
|
}
|
|
|
|
@action
|
|
async onClick(event) {
|
|
if (this.expanded && this.untriggers.includes("click")) {
|
|
return await this.onUntrigger(event);
|
|
}
|
|
|
|
await this.onTrigger(event);
|
|
}
|
|
|
|
@action
|
|
async onMouseLeave(event) {
|
|
if (this.untriggers.includes("hover")) {
|
|
await this.onUntrigger(event);
|
|
}
|
|
}
|
|
|
|
@action
|
|
async onTrigger() {
|
|
await this.options.beforeTrigger?.(this);
|
|
await this.show();
|
|
}
|
|
|
|
@action
|
|
async onUntrigger() {
|
|
await this.close();
|
|
}
|
|
|
|
@action
|
|
destroy() {
|
|
this.tearDownListeners();
|
|
}
|
|
}
|