From 077b291051ad2e7c2f2ea7851c927537ca351f41 Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Mon, 23 Dec 2024 17:16:30 +0300 Subject: [PATCH] fix #334 Select popup positioning when resizing window --- .../domino/ui/config/ZIndexConfig.java | 4 +- .../domino/ui/dialogs/AbstractDialog.java | 6 ++ .../ui/dialogs/DefaultZIndexManager.java | 31 ++++++--- .../domino/ui/dialogs/ModalBackDrop.java | 2 +- .../domino/ui/dialogs/ZIndexManager.java | 3 +- .../dominokit/domino/ui/layout/AppLayout.java | 22 ++++-- .../org/dominokit/domino/ui/menu/Menu.java | 67 +++++++++++++++++-- .../dominokit/domino/ui/menu/MenuItem.java | 6 ++ .../domino/ui/popover/BasePopover.java | 6 ++ .../dominokit/domino/ui/search/Search.java | 2 +- .../domino/ui/utils/BaseDominoElement.java | 31 ++++++++- .../domino/ui/utils/HasZIndexLayer.java | 45 +++++++++++++ .../dominokit/domino/ui/utils/IsPopup.java | 2 +- .../dui-components/domino-ui-app-layout.css | 22 +++--- .../dui-components/domino-ui-notification.css | 2 +- 15 files changed, 213 insertions(+), 38 deletions(-) create mode 100644 domino-ui/src/main/java/org/dominokit/domino/ui/utils/HasZIndexLayer.java diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/config/ZIndexConfig.java b/domino-ui/src/main/java/org/dominokit/domino/ui/config/ZIndexConfig.java index bf50f8b04..62722af7c 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/config/ZIndexConfig.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/config/ZIndexConfig.java @@ -27,12 +27,12 @@ public interface ZIndexConfig extends ComponentConfig { /** * Use this method to define the default initial start z-index * - *

Defaults to : {@code 8388635} + *

Defaults to : {@code 10} * * @return integer z-index */ default int getInitialZIndex() { - return 8388635; + return 10; } /** diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/dialogs/AbstractDialog.java b/domino-ui/src/main/java/org/dominokit/domino/ui/dialogs/AbstractDialog.java index f99c13f56..8f96d5c1b 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/dialogs/AbstractDialog.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/dialogs/AbstractDialog.java @@ -116,6 +116,7 @@ public class AbstractDialog> public AbstractDialog() { element = div() + .setZIndexLayer(ZIndexLayer.Z_LAYER_3) .addCss(dui_modal_box, dui_hidden) .appendChild( modalElement = @@ -696,6 +697,11 @@ public T setDefaultFocusElement(IsElement defaultFocusElement) { return (T) this; } + @Override + public void resetZIndexLayer() { + // Dialogs should never rest their base layer.; + } + /** * Checks if the dialog is currently open. * diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/dialogs/DefaultZIndexManager.java b/domino-ui/src/main/java/org/dominokit/domino/ui/dialogs/DefaultZIndexManager.java index 18ddb83b6..fca344960 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/dialogs/DefaultZIndexManager.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/dialogs/DefaultZIndexManager.java @@ -21,11 +21,14 @@ import java.util.ArrayList; import java.util.Deque; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Optional; import org.dominokit.domino.ui.config.HasComponentConfig; import org.dominokit.domino.ui.config.ZIndexConfig; +import org.dominokit.domino.ui.utils.HasZIndexLayer; import org.dominokit.domino.ui.utils.IsPopup; /** @@ -48,6 +51,7 @@ public class DefaultZIndexManager implements ZIndexManager, HasComponentConfig> modals = new LinkedList<>(); private final List listeners = new ArrayList<>(); + private Map counters = new HashMap<>(); /** * Calculates and returns the next z-index value. @@ -55,12 +59,18 @@ public class DefaultZIndexManager implements ZIndexManager, HasComponentConfig element) { + HasZIndexLayer.ZIndexLayer layer = element.getZIndexLayer(); + + if (isNull(layer)) { + layer = HasZIndexLayer.ZIndexLayer.Z_LAYER_1; + } + if (!counters.containsKey(layer)) { + counters.put(layer, layer.getzIndexOffset() + getConfig().getInitialZIndex()); } - currentZIndex += getConfig().getzIndexIncrement(); - return currentZIndex; + int nextZIndex = counters.get(layer) + getConfig().getzIndexIncrement(); + counters.put(layer, nextZIndex); + return nextZIndex; } /** @@ -72,7 +82,7 @@ public Integer getNextZIndex() { @Override public void onPopupOpen(IsPopup popup) { if (popup.isModal()) { - Integer nextZIndex = getNextZIndex(); + Integer nextZIndex = getNextZIndex(popup); ModalBackDrop.INSTANCE.setZIndex(nextZIndex); if (!ModalBackDrop.INSTANCE.isAttached()) { elements.body().appendChild(ModalBackDrop.INSTANCE); @@ -80,8 +90,9 @@ public void onPopupOpen(IsPopup popup) { modals.push(popup); } - Integer next = getNextZIndex(); + Integer next = getNextZIndex(popup); popup.setZIndex(next); + popup.setZIndexLayer(popup.getZIndexLayer()); listeners.forEach( listener -> listener.onZIndexChange(new ZIndexListener.ZIndexInfo(popup, modals))); } @@ -96,9 +107,9 @@ public void onPopupClose(IsPopup popup) { if (popup.isModal()) { modals.remove(popup); if (!modals.isEmpty()) { - Integer backdropZIndex = getNextZIndex(); + Integer backdropZIndex = getNextZIndex(popup); ModalBackDrop.INSTANCE.setZIndex(backdropZIndex); - Integer modalZIndex = getNextZIndex(); + Integer modalZIndex = getNextZIndex(popup); modals.peek().setZIndex(modalZIndex); listeners.forEach( listener -> @@ -106,6 +117,8 @@ public void onPopupClose(IsPopup popup) { } else { ModalBackDrop.INSTANCE.remove(); } + } else { + popup.resetZIndexLayer(); } } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/dialogs/ModalBackDrop.java b/domino-ui/src/main/java/org/dominokit/domino/ui/dialogs/ModalBackDrop.java index c43f9dadf..344c57ac0 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/dialogs/ModalBackDrop.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/dialogs/ModalBackDrop.java @@ -55,7 +55,7 @@ public class ModalBackDrop extends BaseDominoElement element); /** * Notifies the manager that a popup has been opened. diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/layout/AppLayout.java b/domino-ui/src/main/java/org/dominokit/domino/ui/layout/AppLayout.java index c42ea027a..1acb0836b 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/layout/AppLayout.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/layout/AppLayout.java @@ -103,18 +103,26 @@ public AppLayout() { body = section() .addCss(dui_body) - .appendChild(content = section().addCss(dui_content))); + .appendChild( + content = + section() + .addCss(dui_content) + .setZIndexLayer(ZIndexLayer.Z_LAYER_1))); header = - LazyChild.of(header().addCss(dui_header), body) + LazyChild.of(header().addCss(dui_header).setZIndexLayer(ZIndexLayer.Z_LAYER_2), body) .whenInitialized(() -> layout.addCss(dui_has_header)); navBar = LazyChild.of(NavBar.create(), header); footer = - LazyChild.of(section().addCss(dui_footer), body) + LazyChild.of(section().addCss(dui_footer).setZIndexLayer(ZIndexLayer.Z_LAYER_2), body) .whenInitialized(() -> layout.addCss(dui_has_footer)); leftDrawerToggle = initLeftDrawerToggle(leftToggleIcon); leftDrawer = LazyChild.of( - section().addCss(dui_left_drawer).addClickListener(Event::stopPropagation), layout) + section() + .addCss(dui_left_drawer) + .setZIndexLayer(ZIndexLayer.Z_LAYER_2) + .addClickListener(Event::stopPropagation), + layout) .whenInitialized(leftDrawerToggle::get); leftDrawer.whenInitialized( () -> { @@ -140,7 +148,11 @@ public AppLayout() { rightDrawerToggle = initRightDrawerToggle(rightToggleIcon); rightDrawer = LazyChild.of( - section().addCss(dui_right_drawer).addClickListener(Event::stopPropagation), layout) + section() + .addCss(dui_right_drawer) + .setZIndexLayer(ZIndexLayer.Z_LAYER_2) + .addClickListener(Event::stopPropagation), + layout) .whenInitialized(rightDrawerToggle::get); rightDrawer.whenInitialized( diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/menu/Menu.java b/domino-ui/src/main/java/org/dominokit/domino/ui/menu/Menu.java index 9983cd032..84ab232fb 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/menu/Menu.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/menu/Menu.java @@ -16,14 +16,36 @@ package org.dominokit.domino.ui.menu; import static elemental2.dom.DomGlobal.document; +import static elemental2.dom.DomGlobal.window; import static java.util.Objects.isNull; import static java.util.Objects.nonNull; -import static org.dominokit.domino.ui.utils.Domino.*; +import static org.dominokit.domino.ui.utils.Domino.a; +import static org.dominokit.domino.ui.utils.Domino.div; +import static org.dominokit.domino.ui.utils.Domino.dui_order_first; +import static org.dominokit.domino.ui.utils.Domino.dui_order_last; +import static org.dominokit.domino.ui.utils.Domino.elementOf; +import static org.dominokit.domino.ui.utils.Domino.li; +import static org.dominokit.domino.ui.utils.Domino.ul; import static org.dominokit.domino.ui.utils.PopupsCloser.DOMINO_UI_AUTO_CLOSABLE; -import elemental2.dom.*; +import elemental2.dom.DomGlobal; +import elemental2.dom.Element; +import elemental2.dom.Event; import elemental2.dom.EventListener; -import java.util.*; +import elemental2.dom.HTMLDivElement; +import elemental2.dom.HTMLElement; +import elemental2.dom.HTMLLIElement; +import elemental2.dom.KeyboardEvent; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import jsinterop.base.Js; import org.dominokit.domino.ui.IsElement; import org.dominokit.domino.ui.config.HasComponentConfig; @@ -45,7 +67,19 @@ import org.dominokit.domino.ui.search.SearchBox; import org.dominokit.domino.ui.style.BooleanCssClass; import org.dominokit.domino.ui.style.Elevation; -import org.dominokit.domino.ui.utils.*; +import org.dominokit.domino.ui.utils.AppendStrategy; +import org.dominokit.domino.ui.utils.BaseDominoElement; +import org.dominokit.domino.ui.utils.ChildHandler; +import org.dominokit.domino.ui.utils.DominoElement; +import org.dominokit.domino.ui.utils.DominoUIConfig; +import org.dominokit.domino.ui.utils.HasSelectionListeners; +import org.dominokit.domino.ui.utils.IsPopup; +import org.dominokit.domino.ui.utils.KeyboardNavigation; +import org.dominokit.domino.ui.utils.LazyChild; +import org.dominokit.domino.ui.utils.PopupsCloser; +import org.dominokit.domino.ui.utils.PrefixAddOn; +import org.dominokit.domino.ui.utils.Separator; +import org.dominokit.domino.ui.utils.SubheaderAddon; /** * Represents a UI Menu component that supports different configurations, items, and behaviors. @@ -164,6 +198,7 @@ public class Menu extends BaseDominoElement> private boolean closeOnBlur = DominoUIConfig.CONFIG.isClosePopupOnBlur(); private OpenMenuCondition openMenuCondition = (menu) -> true; private List mediaQueryRecords = new ArrayList<>(); + private EventListener windowResizeListener; /** * Factory method to create a new Menu instance. @@ -184,6 +219,20 @@ public Menu() { backArrowContainer = div().addCss(dui_order_first, dui_menu_back_icon); init(this); + windowResizeListener = evt -> position(); + nowAndWhenAttached( + () -> { + if (isDropDown()) { + window.addEventListener("resize", windowResizeListener); + } + }); + onDetached( + (target, mutationRecord) -> { + if (isDropDown()) { + window.removeEventListener("resize", windowResizeListener); + } + }); + EventListener addMissingEventListener = evt -> { evt.preventDefault(); @@ -1974,6 +2023,16 @@ public Menu setPreserveSelectionStyles(boolean preserveSelectionStyles) { return this; } + @Override + public ZIndexLayer getZIndexLayer() { + if (isDropDown()) { + return getTarget() + .map(t -> t.getTargetElement().getZIndexLayer()) + .orElse(ZIndexLayer.Z_LAYER_1); + } + return super.getZIndexLayer(); + } + /** Represents a handler for a group of menu items. */ @FunctionalInterface public interface MenuItemsGroupHandler> { diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/menu/MenuItem.java b/domino-ui/src/main/java/org/dominokit/domino/ui/menu/MenuItem.java index b4469d30c..61c65020b 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/menu/MenuItem.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/menu/MenuItem.java @@ -131,6 +131,12 @@ public SpanElement getTextElement() { return textElement; } + @Override + public ZIndexLayer getZIndexLayer() { + ZIndexLayer layer = menu.getZIndexLayer(); + return layer; + } + /** * Searches for a given token in the text and description of the menu item. * diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/popover/BasePopover.java b/domino-ui/src/main/java/org/dominokit/domino/ui/popover/BasePopover.java index 5c8b5f986..6c121424b 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/popover/BasePopover.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/popover/BasePopover.java @@ -451,6 +451,12 @@ public T setCloseOnBlur(boolean closeOnBlur) { return (T) this; } + @Override + public ZIndexLayer getZIndexLayer() { + ZIndexLayer layer = elementOf(targetElement).getZIndexLayer(); + return layer; + } + /** * Gets the DOM element representing the popover. * diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/search/Search.java b/domino-ui/src/main/java/org/dominokit/domino/ui/search/Search.java index 47bd3575d..27629ccf6 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/search/Search.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/search/Search.java @@ -169,7 +169,7 @@ public static Search create(boolean autoSearch) { */ public Search open() { expand(); - setZIndex(config().getUIConfig().getZindexManager().getNextZIndex()); + setZIndex(config().getUIConfig().getZindexManager().getNextZIndex(this)); searchInput.element().focus(); return this; } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/utils/BaseDominoElement.java b/domino-ui/src/main/java/org/dominokit/domino/ui/utils/BaseDominoElement.java index 78fc14a20..2a93df2d4 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/utils/BaseDominoElement.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/utils/BaseDominoElement.java @@ -20,6 +20,7 @@ import static org.dominokit.domino.ui.utils.Domino.dui_hidden; import static org.dominokit.domino.ui.utils.Domino.elementOf; import static org.dominokit.domino.ui.utils.Domino.text; +import static org.dominokit.domino.ui.utils.HasZIndexLayer.ZIndexLayer.Z_LAYER_1; import elemental2.core.JsArray; import elemental2.dom.AddEventListenerOptions; @@ -107,7 +108,8 @@ public abstract class BaseDominoElement, HasCollapseListeners, HasAttributes, - HasMeta { + HasMeta, + HasZIndexLayer { static { DominoThemeManager.INSTANCE.applyUserThemes(); @@ -332,6 +334,28 @@ public T setZIndex(int zindex) { return (T) this; } + @Override + public ZIndexLayer getZIndexLayer() { + if (this.hasAttribute(DUI_Z_INDEX_LAYER)) { + return ZIndexLayer.valueOf(getAttribute(DUI_Z_INDEX_LAYER)); + } + if (isNull(parent())) { + return Z_LAYER_1; + } + return parent().getZIndexLayer(); + } + + @Override + public T setZIndexLayer(ZIndexLayer layer) { + setAttribute(DUI_Z_INDEX_LAYER, layer.name()); + return (T) this; + } + + @Override + public void resetZIndexLayer() { + removeAttribute(DUI_Z_INDEX_LAYER); + } + /** * Sets the "tabindex" attribute of the DOM element. * @@ -2200,7 +2224,10 @@ public Node lastChild() { */ @Editor.Ignore public DominoElement parent() { - return elementOf(Js.uncheckedCast(element().parentElement)); + if (nonNull(element().parentElement)) { + return elementOf(Js.uncheckedCast(element().parentElement)); + } + return null; } /** diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/utils/HasZIndexLayer.java b/domino-ui/src/main/java/org/dominokit/domino/ui/utils/HasZIndexLayer.java new file mode 100644 index 000000000..656be4449 --- /dev/null +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/utils/HasZIndexLayer.java @@ -0,0 +1,45 @@ +/* + * Copyright © 2019 Dominokit + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.dominokit.domino.ui.utils; + +public interface HasZIndexLayer { + + String DUI_Z_INDEX_LAYER = "dui-z-index-layer"; + + ZIndexLayer getZIndexLayer(); + + T setZIndexLayer(ZIndexLayer layer); + + void resetZIndexLayer(); + + enum ZIndexLayer { + Z_LAYER_1(110), + Z_LAYER_2(5001000), + Z_LAYER_3(10000000), + Z_LAYER_4(20000000), + ; + + private final int zIndexOffset; + + ZIndexLayer(int zIndexOffset) { + this.zIndexOffset = zIndexOffset; + } + + public int getzIndexOffset() { + return zIndexOffset; + } + } +} diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/utils/IsPopup.java b/domino-ui/src/main/java/org/dominokit/domino/ui/utils/IsPopup.java index 1c2c694c6..c7e0ca8a2 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/utils/IsPopup.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/utils/IsPopup.java @@ -21,7 +21,7 @@ * * @param The type of the component that implements this interface. */ -public interface IsPopup { +public interface IsPopup extends HasZIndexLayer { /** * Opens the popup. diff --git a/domino-ui/src/main/resources/org/dominokit/domino/ui/public/css/domino-ui/dui-components/domino-ui-app-layout.css b/domino-ui/src/main/resources/org/dominokit/domino/ui/public/css/domino-ui/dui-components/domino-ui-app-layout.css index 650b516c5..d0d2168bc 100644 --- a/domino-ui/src/main/resources/org/dominokit/domino/ui/public/css/domino-ui/dui-components/domino-ui-app-layout.css +++ b/domino-ui/src/main/resources/org/dominokit/domino/ui/public/css/domino-ui/dui-components/domino-ui-app-layout.css @@ -20,17 +20,17 @@ --dui-left-drawer-padding-bottom: var(--dui-footer-height); --dui-right-drawer-padding-top: var(--dui-header-height); --dui-right-drawer-padding-bottom: var(--dui-footer-height); - --dui-layout-z-index-offset: 0; - --dui-zindex-offset-0:0; - --dui-zindex-offset-1:100; - --dui-zindex-offset-2:200; - --dui-zindex-offset-3:300; - --dui-zindex-offset-4:400; - --dui-zindex-offset-5:500; - --dui-zindex-offset-6:600; - --dui-zindex-offset-7:700; - --dui-zindex-offset-8:800; - --dui-zindex-offset-9:900; + --dui-layout-z-index-offset: 5000000; + --dui-zindex-offset-0:5000000; + --dui-zindex-offset-1:5000100; + --dui-zindex-offset-2:5000200; + --dui-zindex-offset-3:5000300; + --dui-zindex-offset-4:5000400; + --dui-zindex-offset-5:5000500; + --dui-zindex-offset-6:5000600; + --dui-zindex-offset-7:5000700; + --dui-zindex-offset-8:5000800; + --dui-zindex-offset-9:5000900; --dui-left-drawer-z-index: var(--dui-zindex-offset-1); --dui-right-drawer-z-index: var(--dui-zindex-offset-3); --dui-footer-z-index: var(--dui-zindex-offset-5); diff --git a/domino-ui/src/main/resources/org/dominokit/domino/ui/public/css/domino-ui/dui-components/domino-ui-notification.css b/domino-ui/src/main/resources/org/dominokit/domino/ui/public/css/domino-ui/dui-components/domino-ui-notification.css index dd790673b..990bcf858 100644 --- a/domino-ui/src/main/resources/org/dominokit/domino/ui/public/css/domino-ui/dui-components/domino-ui-notification.css +++ b/domino-ui/src/main/resources/org/dominokit/domino/ui/public/css/domino-ui/dui-components/domino-ui-notification.css @@ -5,7 +5,7 @@ overflow: visible; background: none; text-align: center; - z-index: 9999999; + z-index: 20000000; display: flex; padding: 0 var(--dui-ntfy-left-right-space); pointer-events: none;