mirror of
https://github.com/discourse/discourse.git
synced 2024-12-02 10:36:18 +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
92 lines
2.8 KiB
Plaintext
92 lines
2.8 KiB
Plaintext
import Component from "@glimmer/component";
|
|
import { concat, hash } from "@ember/helper";
|
|
import { htmlSafe } from "@ember/template";
|
|
import { modifier as modifierFn } from "ember-modifier";
|
|
import concatClass from "discourse/helpers/concat-class";
|
|
import closeOnClickOutside from "discourse/modifiers/close-on-click-outside";
|
|
import TrapTab from "discourse/modifiers/trap-tab";
|
|
import DFloatPortal from "float-kit/components/d-float-portal";
|
|
import { getScrollParent } from "float-kit/lib/get-scroll-parent";
|
|
import FloatKitApplyFloatingUi from "float-kit/modifiers/apply-floating-ui";
|
|
import FloatKitCloseOnEscape from "float-kit/modifiers/close-on-escape";
|
|
|
|
export default class DFloatBody extends Component {
|
|
closeOnScroll = modifierFn(() => {
|
|
const firstScrollParent = getScrollParent(this.trigger);
|
|
|
|
const handler = () => {
|
|
this.args.instance.close();
|
|
};
|
|
|
|
firstScrollParent.addEventListener("scroll", handler, { passive: true });
|
|
|
|
return () => {
|
|
firstScrollParent.removeEventListener("scroll", handler);
|
|
};
|
|
});
|
|
|
|
get supportsCloseOnClickOutside() {
|
|
return this.args.instance.expanded && this.options.closeOnClickOutside;
|
|
}
|
|
|
|
get supportsCloseOnEscape() {
|
|
return this.args.instance.expanded && this.options.closeOnEscape;
|
|
}
|
|
|
|
get supportsCloseOnScroll() {
|
|
return this.args.instance.expanded && this.options.closeOnScroll;
|
|
}
|
|
|
|
get trigger() {
|
|
return this.args.instance?.trigger;
|
|
}
|
|
|
|
get content() {
|
|
return this.args.instance?.content;
|
|
}
|
|
|
|
get options() {
|
|
return this.args.instance.options;
|
|
}
|
|
|
|
<template>
|
|
<DFloatPortal
|
|
@inline={{@inline}}
|
|
@portalOutletElement={{@instance.portalOutletElement}}
|
|
>
|
|
<div
|
|
class={{concatClass
|
|
@mainClass
|
|
(if this.options.animated "-animated")
|
|
(if @instance.expanded "-expanded")
|
|
this.options.extraClassName
|
|
}}
|
|
data-identifier={{this.options.identifier}}
|
|
data-content
|
|
aria-labelledby={{@instance.id}}
|
|
aria-expanded={{if @instance.expanded "true" "false"}}
|
|
role={{@role}}
|
|
{{FloatKitApplyFloatingUi this.trigger this.options @instance}}
|
|
{{(if @trapTab (modifier TrapTab autofocus=this.options.autofocus))}}
|
|
{{(if
|
|
this.supportsCloseOnClickOutside
|
|
(modifier
|
|
closeOnClickOutside @instance.close (hash target=this.content)
|
|
)
|
|
)}}
|
|
{{(if
|
|
this.supportsCloseOnEscape
|
|
(modifier FloatKitCloseOnEscape @instance.close)
|
|
)}}
|
|
{{(if this.supportsCloseOnScroll (modifier this.closeOnScroll))}}
|
|
style={{htmlSafe (concat "max-width: " this.options.maxWidth "px")}}
|
|
...attributes
|
|
>
|
|
<div class={{@innerClass}}>
|
|
{{yield}}
|
|
</div>
|
|
</div>
|
|
</DFloatPortal>
|
|
</template>
|
|
}
|