diff --git a/client/src/controllers/DropdownController.ts b/client/src/controllers/DropdownController.ts index e1533bfb9869..b80229dda1ce 100644 --- a/client/src/controllers/DropdownController.ts +++ b/client/src/controllers/DropdownController.ts @@ -95,20 +95,22 @@ export class DropdownController extends Controller { static targets = ['toggle', 'content']; static values = { hideOnClick: { default: false, type: Boolean }, + keepMounted: { default: false, type: Boolean }, offset: Array, theme: { default: 'dropdown' as TippyTheme, type: String }, }; // Hide on click *inside* the dropdown. Differs from tippy's hideOnClick // option for outside clicks that defaults to true and we don't yet expose it. - declare hideOnClickValue: boolean; - declare offsetValue: [number, number]; + declare readonly hideOnClickValue: boolean; + declare readonly keepMountedValue: boolean; + declare readonly offsetValue: [number, number]; + declare readonly hasOffsetValue: boolean; + declare readonly themeValue: TippyTheme; declare readonly contentTarget: HTMLDivElement; declare readonly hasContentTarget: boolean; - declare readonly hasOffsetValue: boolean; declare readonly toggleTarget: HTMLButtonElement; - declare readonly themeValue: TippyTheme; tippy?: Instance; @@ -144,10 +146,22 @@ export class DropdownController extends Controller { }); } - const onShow = () => { + const onCreate = (instance: Instance) => { + if (this.keepMountedValue) { + const { popper } = instance; + this.element.append(popper); + popper.hidden = true; + } + }; + + const onShow = (instance: Instance) => { if (hoverTooltipInstance) { hoverTooltipInstance.disable(); } + if (this.keepMountedValue) { + const { popper } = instance; + popper.hidden = false; + } }; const onShown = () => { @@ -161,6 +175,14 @@ export class DropdownController extends Controller { } }; + const onHidden = (instance: Instance) => { + if (this.keepMountedValue) { + const { popper } = instance; + this.element.append(popper); + popper.hidden = true; + } + }; + return { ...(this.hasContentTarget ? { content: this.contentTarget as Content } @@ -171,9 +193,11 @@ export class DropdownController extends Controller { ...(this.hasOffsetValue && { offset: this.offsetValue }), getReferenceClientRect: () => this.reference.getBoundingClientRect(), theme: this.themeValue, + onCreate, onShow, onShown, onHide, + onHidden, }; } diff --git a/wagtail/admin/templates/wagtailadmin/shared/dropdown/dropdown.html b/wagtail/admin/templates/wagtailadmin/shared/dropdown/dropdown.html index 15e77cd16379..d68bc38f2525 100644 --- a/wagtail/admin/templates/wagtailadmin/shared/dropdown/dropdown.html +++ b/wagtail/admin/templates/wagtailadmin/shared/dropdown/dropdown.html @@ -14,12 +14,21 @@ - `toggle_classname` (string?) - additional toggle classes - `toggle_tooltip_offset` (string?) - Tooltip offset prop - `hide_on_click` (boolean?) - Whether or not the tooltip should hide when clicking inside + - `keep_mounted` (boolean?) - Whether or not the tooltip should keep its DOM node mounted when hidden - `children` - Dropdown contents (`a` and `button` elements only) {% endcomment %} {% fragment as class %}{% classnames 'w-dropdown' classname %}{% if theme %} w-dropdown--{{ theme }}{% endif %}{% endfragment %} -
+