discourse/app/assets/javascripts/float-kit/addon/lib/d-tooltip-instance.js
Joffrey JAFFEUX fe16633a0c
DEV: allows for multiple menus/tooltips (#26823)
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
2024-05-07 23:48:44 +02:00

108 lines
2.5 KiB
JavaScript

import { tracked } from "@glimmer/tracking";
import { setOwner } from "@ember/application";
import { action } from "@ember/object";
import { guidFor } from "@ember/object/internals";
import { service } from "@ember/service";
import { TOOLTIP } from "float-kit/lib/constants";
import FloatKitInstance from "float-kit/lib/float-kit-instance";
export default class DTooltipInstance extends FloatKitInstance {
@service tooltip;
/**
* Indicates whether the tooltip is expanded or not.
* @property {boolean} expanded - Tracks the state of tooltip expansion, initially set to false.
*/
@tracked expanded = false;
/**
* Specifies whether the trigger for opening/closing the tooltip is detached from the tooltip itself.
* This is the case when a tooltip is trigger programmaticaly instead of through the <DTooltip /> component.
* @property {boolean} detachedTrigger - Tracks whether the trigger is detached, initially set to false.
*/
@tracked detachedTrigger = false;
/**
* Configuration options for the DTooltipInstance.
* @property {Object} options - Options object that configures the tooltip behavior and display.
*/
@tracked options;
@tracked _trigger;
constructor(owner, options = {}) {
super(...arguments);
setOwner(this, owner);
this.options = { ...TOOLTIP.options, ...options };
}
get trigger() {
return this._trigger;
}
set trigger(element) {
this._trigger = element;
this.id = element.id || guidFor(element);
this.setupListeners();
}
get portalOutletElement() {
return document.getElementById("d-tooltip-portals");
}
@action
async show() {
await this.tooltip.show(this);
await super.show(...arguments);
}
@action
async close() {
await this.tooltip.close(this);
await super.close(...arguments);
}
@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();
}
}