mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-23 06:30:50 +08:00
As much as possible I would like us to avoid having to go the with a global event listener on click/mouseover. For now I have removed all cases of `data-tooltip`, if we clearly identify a use case of a global event listener we might reconsider this. The following changes are also included: - by default tooltips won't attempt to focus first focusable element anymore - tooltip will now use `cursor: pointer` by default - a new service has been introduced: `InternalTooltip` which is responsible to track the current instance displayed by a `<DTooltip />`. Portal elements when replaced are not properly cleaned and I couldn't figure out a way to have a proper hook to ensure the previous `DTooltipInstance` is properly set as not expanded; this problem was very visible when using a tooltip as interactive and hovering another tooltip, which would replace the interactive tooltip as not closed.
110 lines
3.1 KiB
JavaScript
Vendored
110 lines
3.1 KiB
JavaScript
Vendored
import Component from "@glimmer/component";
|
|
import { tracked } from "@glimmer/tracking";
|
|
import { getOwner } from "@ember/application";
|
|
import { inject as service } from "@ember/service";
|
|
import { modifier } from "ember-modifier";
|
|
import concatClass from "discourse/helpers/concat-class";
|
|
import icon from "discourse-common/helpers/d-icon";
|
|
import DFloatBody from "float-kit/components/d-float-body";
|
|
import DTooltipInstance from "float-kit/lib/d-tooltip-instance";
|
|
import and from "truth-helpers/helpers/and";
|
|
|
|
export default class DTooltip extends Component {
|
|
@service tooltip;
|
|
@service internalTooltip;
|
|
|
|
@tracked tooltipInstance = null;
|
|
|
|
registerTrigger = modifier((element) => {
|
|
const options = {
|
|
...this.args,
|
|
...{
|
|
listeners: true,
|
|
beforeTrigger: (instance) => {
|
|
this.internalTooltip.activeTooltip?.close?.();
|
|
this.internalTooltip.activeTooltip = instance;
|
|
},
|
|
},
|
|
};
|
|
const instance = new DTooltipInstance(getOwner(this), element, options);
|
|
|
|
this.tooltipInstance = instance;
|
|
|
|
return () => {
|
|
instance.destroy();
|
|
|
|
if (this.isDestroying) {
|
|
this.tooltipInstance = null;
|
|
}
|
|
};
|
|
});
|
|
|
|
get options() {
|
|
return this.tooltipInstance?.options;
|
|
}
|
|
|
|
get componentArgs() {
|
|
return {
|
|
close: this.tooltip.close,
|
|
data: this.options.data,
|
|
};
|
|
}
|
|
|
|
<template>
|
|
<span
|
|
class={{concatClass
|
|
"fk-d-tooltip__trigger"
|
|
(if this.tooltipInstance.expanded "-expanded")
|
|
}}
|
|
role="button"
|
|
id={{this.tooltipInstance.id}}
|
|
data-identifier={{this.options.identifier}}
|
|
data-trigger
|
|
aria-expanded={{if this.tooltipInstance.expanded "true" "false"}}
|
|
{{this.registerTrigger}}
|
|
...attributes
|
|
>
|
|
<div class="fk-d-tooltip__trigger-container">
|
|
{{#if (has-block "trigger")}}
|
|
<div>
|
|
{{yield this.componentArgs to="trigger"}}
|
|
</div>
|
|
{{else}}
|
|
{{#if @icon}}
|
|
<span class="fk-d-tooltip__icon">
|
|
{{~icon @icon~}}
|
|
</span>
|
|
{{/if}}
|
|
{{#if @label}}
|
|
<span class="fk-d-tooltip__label">{{@label}}</span>
|
|
{{/if}}
|
|
{{/if}}
|
|
</div>
|
|
</span>
|
|
|
|
{{#if this.tooltipInstance.expanded}}
|
|
<DFloatBody
|
|
@instance={{this.tooltipInstance}}
|
|
@trapTab={{and this.options.interactive this.options.trapTab}}
|
|
@mainClass="fk-d-tooltip"
|
|
@innerClass="fk-d-tooltip__inner-content"
|
|
@role="tooltip"
|
|
@inline={{this.options.inline}}
|
|
@portalOutletElement={{this.tooltip.portalOutletElement}}
|
|
>
|
|
{{#if (has-block)}}
|
|
{{yield this.componentArgs}}
|
|
{{else if (has-block "content")}}
|
|
{{yield this.componentArgs to="content"}}
|
|
{{else if this.options.component}}
|
|
<this.options.component
|
|
@data={{this.options.data}}
|
|
@close={{this.tooltipInstance.close}}
|
|
/>
|
|
{{else if this.options.content}}
|
|
{{this.options.content}}
|
|
{{/if}}
|
|
</DFloatBody>
|
|
{{/if}}
|
|
</template>
|
|
}
|