From a6b3536fe40a8ddb817da5e04e08b5a93f0913e4 Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Wed, 19 Feb 2025 13:02:10 +0300 Subject: [PATCH] fix #1009 Tree does not collapse reliable --- .../domino/ui/button/BaseButton.java | 8 - .../collapsible/HeightCollapseStrategy.java | 89 +++---- .../TreeHeightCollapseStrategy.java | 222 ------------------ .../domino/ui/config/TreeConfig.java | 5 +- .../domino/ui/style/HasWaveEffect.java | 15 -- .../dominokit/domino/ui/style/WaveStyle.java | 64 ----- .../org/dominokit/domino/ui/style/Waves.java | 192 ++++----------- .../domino/ui/style/WavesElement.java | 13 - .../domino/ui/style/WavesSupport.java | 54 +---- .../dominokit/domino/ui/tree/TreeNode.java | 12 +- .../domino/ui/utils/BaseDominoElement.java | 12 - .../dui-components/domino-ui-collapse.css | 8 + .../dui-components/domino-ui-waves.css | 129 ++-------- 13 files changed, 143 insertions(+), 680 deletions(-) delete mode 100644 domino-ui/src/main/java/org/dominokit/domino/ui/collapsible/TreeHeightCollapseStrategy.java delete mode 100644 domino-ui/src/main/java/org/dominokit/domino/ui/style/WaveStyle.java diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/button/BaseButton.java b/domino-ui/src/main/java/org/dominokit/domino/ui/button/BaseButton.java index 4e3738587..28325851a 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/button/BaseButton.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/button/BaseButton.java @@ -17,7 +17,6 @@ import static java.util.Objects.nonNull; import static org.dominokit.domino.ui.button.ButtonStyles.*; -import static org.dominokit.domino.ui.utils.Domino.*; import static org.dominokit.domino.ui.utils.Domino.div; import static org.dominokit.domino.ui.utils.Domino.span; @@ -29,7 +28,6 @@ import org.dominokit.domino.ui.elements.SpanElement; import org.dominokit.domino.ui.icons.Icon; import org.dominokit.domino.ui.style.BooleanCssClass; -import org.dominokit.domino.ui.style.WaveStyle; import org.dominokit.domino.ui.style.WavesElement; import org.dominokit.domino.ui.utils.AcceptDisable; import org.dominokit.domino.ui.utils.ChildHandler; @@ -149,7 +147,6 @@ public HTMLElement getClickableElement() { */ public B circle() { buttonElement.addCss(ButtonStyles.dui_circle); - applyCircleWaves(); return (B) this; } @@ -265,9 +262,4 @@ public HTMLElement element() { public B asButton() { return (B) this; } - - private void applyCircleWaves() { - setWaveStyle(WaveStyle.CIRCLE); - setWaveStyle(WaveStyle.FLOAT); - } } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/collapsible/HeightCollapseStrategy.java b/domino-ui/src/main/java/org/dominokit/domino/ui/collapsible/HeightCollapseStrategy.java index 1d552b6ed..8d2b631ed 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/collapsible/HeightCollapseStrategy.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/collapsible/HeightCollapseStrategy.java @@ -17,7 +17,6 @@ import static org.dominokit.domino.ui.collapsible.Collapsible.DUI_COLLAPSED; import static org.dominokit.domino.ui.style.GenericCss.dui_transition_none; -import static org.dominokit.domino.ui.utils.Domino.*; import static org.dominokit.domino.ui.utils.ElementsFactory.elements; import elemental2.dom.AddEventListenerOptions; @@ -26,7 +25,6 @@ import elemental2.dom.EventListener; import org.dominokit.domino.ui.utils.DominoElement; import org.dominokit.domino.ui.utils.DominoId; -import org.dominokit.domino.ui.utils.IsCollapsible; /** * An implementation of {@link org.dominokit.domino.ui.collapsible.CollapseStrategy} that uses the @@ -35,11 +33,10 @@ public class HeightCollapseStrategy implements CollapseStrategy, CollapsibleStyles { private static final String EXPAND_COLLAPSE_HEIGHT_VAR = "--dui-element-expand-collapse-height-"; - private static final String DUI_EXPANDED_HEIGHT = "dui-expanded-height"; - private static final String DUI_EXPAND_COLLAPSE_VAR = "dui-expand-collapse-var"; private final CollapsibleDuration transition; private final String heightVar; + private final String initialHeight; private CollapsibleHandlers handlers; private DominoElement target; @@ -48,31 +45,50 @@ public HeightCollapseStrategy() { this(CollapsibleDuration._300ms); } + /** Create a HeightCollapseStrategy with a default duration of 300ms */ + public HeightCollapseStrategy(String initialHeight) { + this(initialHeight, CollapsibleDuration._300ms); + } + /** * Create a HeightCollapseStrategy with the provided duration * * @param transition The height animation {@link CollapsibleDuration} */ public HeightCollapseStrategy(CollapsibleDuration transition) { + this("auto", transition); + } + + /** + * Create a HeightCollapseStrategy with the provided duration + * + * @param transition The height animation {@link CollapsibleDuration} + */ + public HeightCollapseStrategy(String initialHeight, CollapsibleDuration transition) { this.transition = transition; this.heightVar = DominoId.unique(EXPAND_COLLAPSE_HEIGHT_VAR); + this.initialHeight = initialHeight; } /** @dominokit-site-ignore {@inheritDoc} */ @Override public void init(Element element, CollapsibleHandlers handlers) { this.target = elements.elementOf(element); - this.target.setAttribute(DUI_EXPAND_COLLAPSE_VAR, this.heightVar); - this.target.setCssProperty("height", "var(" + this.heightVar + ", auto)"); + this.target.setCssProperty("height", "var(" + this.heightVar + "," + this.initialHeight + ")"); this.handlers = handlers; - this.target.addCss(dui_height_collapsed_overflow).addCss(transition.getStyle()); + this.target + .addCss(dui_height_collapsed_overflow, dui_height_collapsed) + .addCss(transition.getStyle()); } /** @dominokit-site-ignore {@inheritDoc} */ @Override public void cleanup(Element element) { - elements.elementOf(element).addCss(dui_height_collapsed_overflow).addCss(transition.getStyle()); - element.removeAttribute("dom-ui-collapse-height"); + elements + .elementOf(element) + .removeCss(dui_height_collapsed_overflow) + .removeCss(dui_height_collapsed) + .removeCss(transition.getStyle()); } /** @dominokit-site-ignore {@inheritDoc} */ @@ -80,34 +96,28 @@ public void cleanup(Element element) { public void expand(Element element) { this.target.nowOrWhenAttached( () -> { + boolean noTransition = dui_transition_none.isAppliedTo(this.target); + this.target.addCss(dui_transition_none); + this.target.setCssProperty(this.heightVar, "auto"); + this.target.setAttribute("dui-default-height", this.target.element().scrollHeight); + this.target.setCssProperty(this.heightVar, "0px"); + if (!noTransition) { + this.target.removeCss(dui_transition_none); + } this.handlers.onBeforeExpand().run(); expandElement(element); }); } - private double getActualHeight() { - double contentHeight = - this.target.childElements().stream() - .filter(IsCollapsible::isExpanded) - .mapToDouble(e -> e.getBoundingClientRect().height) - .sum(); - - double elementHeight = this.target.getBoundingClientRect().height; - return Math.max(elementHeight, contentHeight); - } - private void expandElement(Element element) { if (dui_transition_none.isAppliedTo(this.target)) { - this.target.setCssProperty(this.heightVar, "auto"); this.target.removeAttribute(DUI_COLLAPSED); handlers.onExpandCompleted().run(); } else { EventListener stopListener = evt -> { - handlers.onExpandCompleted().run(); - double actualHeight = getActualHeight(); this.target.setCssProperty(this.heightVar, "auto"); - this.target.setAttribute(DUI_EXPANDED_HEIGHT, actualHeight); + handlers.onExpandCompleted().run(); }; AddEventListenerOptions addEventListenerOptions = AddEventListenerOptions.create(); @@ -125,19 +135,19 @@ private void expandElement(Element element) { .element() .addEventListener("oanimationend", stopListener, addEventListenerOptions); this.target.element().addEventListener("animationend", stopListener, addEventListenerOptions); + } + + this.target.removeAttribute(DUI_COLLAPSED); + this.target.setCssProperty(this.heightVar, getActualHeight() + "px"); + } - this.target.removeCss(dui_height_collapsed); - String expandedHeight = this.target.getAttribute(DUI_EXPANDED_HEIGHT); - - if ("auto".equals(expandedHeight)) { - double actualHeight = getActualHeight(); - this.target.setCssProperty(this.heightVar, actualHeight + "px"); - this.target.removeAttribute(DUI_COLLAPSED); - } else { - this.target.setCssProperty(this.heightVar, expandedHeight + "px"); - this.target.removeAttribute(DUI_COLLAPSED); - } + private double getActualHeight() { + if (this.target.hasAttribute("dui-default-height")) { + return Math.max( + Double.parseDouble(this.target.getAttribute("dui-default-height")), + this.target.element().scrollHeight); } + return this.target.element().scrollHeight; } /** @dominokit-site-ignore {@inheritDoc} */ @@ -147,9 +157,7 @@ public void collapse(Element element) { this.target.apply( self -> { if (self.isAttached()) { - double actualHeight = getActualHeight(); - this.target.setAttribute(DUI_EXPANDED_HEIGHT, actualHeight); - this.target.setCssProperty(this.heightVar, actualHeight + "px"); + this.target.setCssProperty(this.heightVar, getActualHeight() + "px"); this.handlers.onBeforeCollapse().run(); collapseElement(element); @@ -157,7 +165,8 @@ public void collapse(Element element) { } else { self.onAttached( (e, mutationRecord) -> { - this.target.setAttribute(DUI_EXPANDED_HEIGHT, "auto"); + + // this.target.setAttribute(DUI_EXPANDED_HEIGHT, "auto"); this.target.setCssProperty(this.heightVar, "auto"); this.handlers.onBeforeCollapse().run(); this.target.addCss(dui_transition_none); @@ -175,13 +184,11 @@ private void collapseElement(Element element) { if (dui_transition_none.isAppliedTo(this.target)) { this.target.setAttribute(DUI_COLLAPSED, "true"); this.target.setCssProperty(this.heightVar, "0px"); - this.target.addCss(dui_height_collapsed); } else { DomGlobal.requestAnimationFrame( timestamp -> { this.target.setAttribute(DUI_COLLAPSED, "true"); this.target.setCssProperty(this.heightVar, "0px"); - this.target.addCss(dui_height_collapsed); }); } } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/collapsible/TreeHeightCollapseStrategy.java b/domino-ui/src/main/java/org/dominokit/domino/ui/collapsible/TreeHeightCollapseStrategy.java deleted file mode 100644 index 14695fbfb..000000000 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/collapsible/TreeHeightCollapseStrategy.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * 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.collapsible; - -import static org.dominokit.domino.ui.collapsible.Collapsible.DUI_COLLAPSED; -import static org.dominokit.domino.ui.style.GenericCss.dui_transition_none; -import static org.dominokit.domino.ui.utils.ElementsFactory.elements; - -import elemental2.dom.AddEventListenerOptions; -import elemental2.dom.DomGlobal; -import elemental2.dom.Element; -import elemental2.dom.EventListener; -import org.dominokit.domino.ui.tree.TreeNode; -import org.dominokit.domino.ui.utils.DominoId; -import org.dominokit.domino.ui.utils.IsCollapsible; - -/** - * An implementation of {@link CollapseStrategy} that is meant to be used with the {@link - * org.dominokit.domino.ui.tree.Tree} component - */ -public class TreeHeightCollapseStrategy implements CollapseStrategy, CollapsibleStyles { - - private static final String EXPAND_COLLAPSE_HEIGHT_VAR = - "--dui-tree-item-expand-collapse-height-"; - private static final String DUI_COLLAPSED_HEIGHT = "dui-collapsed-height"; - private static final String DUI_EXPANDED_HEIGHT = "dui-expanded-height"; - private static final String DUI_EXPAND_COLLAPSE_VAR = "dui-expand-collapse-var"; - - private final CollapsibleDuration transition; - private final String heightVar; - private CollapsibleHandlers handlers; - private final TreeNode node; - private boolean expanding = false; - private boolean collapsing = false; - - /** - * Constructor for TreeHeightCollapseStrategy. - * - * @param node a {@link org.dominokit.domino.ui.tree.TreeItem} object - */ - public TreeHeightCollapseStrategy(TreeNode node) { - this(node, CollapsibleDuration._300ms); - } - - /** - * Constructor for TreeHeightCollapseStrategy. - * - * @param node a {@link org.dominokit.domino.ui.tree.TreeItem} object - * @param transition a {@link CollapsibleDuration} object - */ - public TreeHeightCollapseStrategy(TreeNode node, CollapsibleDuration transition) { - this.node = node; - this.transition = transition; - this.heightVar = DominoId.unique(EXPAND_COLLAPSE_HEIGHT_VAR); - this.node.setAttribute(DUI_EXPAND_COLLAPSE_VAR, this.heightVar); - this.node.setCssProperty("height", "var(" + this.heightVar + ", auto)"); - } - - /** @dominokit-site-ignore {@inheritDoc} */ - @Override - public void init(Element element, CollapsibleHandlers handlers) { - this.handlers = handlers; - this.node.addCss(dui_height_collapsed_overflow).addCss(transition.getStyle()); - this.node.nowOrWhenAttached( - () -> { - double height = node.getBoundingClientRect().height; - node.setAttribute(DUI_COLLAPSED_HEIGHT, height); - }); - - element.setAttribute(DUI_COLLAPSED, true); - } - - /** @dominokit-site-ignore {@inheritDoc} */ - @Override - public void cleanup(Element element) { - elements.elementOf(element).addCss(dui_height_collapsed_overflow).addCss(transition.getStyle()); - element.removeAttribute("dom-ui-collapse-height"); - } - - /** @dominokit-site-ignore {@inheritDoc} */ - @Override - public void expand(Element element) { - node.nowOrWhenAttached( - () -> { - if (!collapsing) { - this.expanding = true; - this.handlers.onBeforeExpand().run(); - double height = node.getBoundingClientRect().height; - node.setAttribute(DUI_COLLAPSED_HEIGHT, height); - node.getSubTree().show(); - node.setCssProperty(this.heightVar, height + "px"); - double expandedHeight = getActualHeight(); - node.setAttribute(DUI_EXPANDED_HEIGHT, expandedHeight); - expandElement(element); - } - }); - } - - private double getActualHeight() { - double expandedHeight = - node.childElements().stream() - .filter(IsCollapsible::isExpanded) - .mapToDouble(e -> e.getBoundingClientRect().height) - .sum(); - return expandedHeight; - } - - private void expandElement(Element element) { - if (dui_transition_none.isAppliedTo(node)) { - node.setCssProperty(this.heightVar, "auto"); - node.removeAttribute(DUI_COLLAPSED); - handlers.onExpandCompleted().run(); - expanding = false; - } else { - EventListener stopListener = - evt -> { - resetParentHeight(node); - node.setCssProperty(this.heightVar, "auto"); - handlers.onExpandCompleted().run(); - expanding = false; - }; - - createAnimationEndListeners(stopListener); - - String expandedHeight = node.getAttribute(DUI_EXPANDED_HEIGHT); - node.setCssProperty(this.heightVar, expandedHeight + "px"); - node.removeAttribute(DUI_COLLAPSED); - } - } - - private void createAnimationEndListeners(EventListener stopListener) { - AddEventListenerOptions addEventListenerOptions = AddEventListenerOptions.create(); - addEventListenerOptions.setOnce(true); - node.element().addEventListener("webkitTransitionEnd", stopListener, addEventListenerOptions); - node.element().addEventListener("MSTransitionEnd", stopListener, addEventListenerOptions); - node.element().addEventListener("mozTransitionEnd", stopListener, addEventListenerOptions); - node.element().addEventListener("oanimationend", stopListener, addEventListenerOptions); - node.element().addEventListener("animationend", stopListener, addEventListenerOptions); - } - - /** @dominokit-site-ignore {@inheritDoc} */ - @Override - public void collapse(Element element) { - if (!expanding) { - collapsing = true; - node.setCssProperty(this.heightVar, getActualHeight() + "px"); - boolean disableAnimation = dui_transition_none.isAppliedTo(node); - node.apply( - self -> { - if (self.isAttached()) { - this.handlers.onBeforeCollapse().run(); - EventListener stopListener = - evt -> { - handlers.onCollapseCompleted().run(); - collapsing = false; - }; - createAnimationEndListeners(stopListener); - collapseElement(element); - } else { - self.onAttached( - (e, mutationRecord) -> { - this.handlers.onBeforeCollapse().run(); - node.addCss(dui_transition_none); - EventListener stopListener = - evt -> { - if (!disableAnimation) { - dui_transition_none.remove(node); - } - handlers.onCollapseCompleted().run(); - collapsing = false; - }; - createAnimationEndListeners(stopListener); - collapseElement(element); - }); - } - }); - } - } - - private void resetParentHeight(TreeNode treeNode) { - treeNode - .getParent() - .ifPresent( - parent -> { - if (parent instanceof TreeNode) { - TreeNode parentItem = (TreeNode) parent; - parentItem.removeCssProperty(parentItem.getAttribute(DUI_EXPAND_COLLAPSE_VAR)); - parent.getParent().ifPresent(treeItem1 -> resetParentHeight(parentItem)); - } - }); - } - - private void collapseElement(Element element) { - if (dui_transition_none.isAppliedTo(node)) { - node.setAttribute(DUI_COLLAPSED, "true"); - node.setCssProperty(this.heightVar, node.getAttribute(DUI_COLLAPSED_HEIGHT) + "px"); - handlers.onCollapseCompleted().run(); - collapsing = false; - } else { - DomGlobal.requestAnimationFrame( - timestamp -> { - node.setAttribute(DUI_COLLAPSED, "true"); - node.setCssProperty(this.heightVar, node.getAttribute(DUI_COLLAPSED_HEIGHT) + "px"); - handlers.onCollapseCompleted().run(); - collapsing = false; - }); - } - } -} diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/config/TreeConfig.java b/domino-ui/src/main/java/org/dominokit/domino/ui/config/TreeConfig.java index d95aa9e71..6299f2fb6 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/config/TreeConfig.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/config/TreeConfig.java @@ -16,8 +16,7 @@ package org.dominokit.domino.ui.config; import java.util.function.Supplier; -import org.dominokit.domino.ui.collapsible.CollapseStrategy; -import org.dominokit.domino.ui.collapsible.TreeHeightCollapseStrategy; +import org.dominokit.domino.ui.collapsible.*; import org.dominokit.domino.ui.tree.TreeNode; /** @@ -35,6 +34,6 @@ public interface TreeConfig extends ComponentConfig { * @return a {@code Supplier} */ default Supplier getTreeDefaultCollapseStrategy(TreeNode node) { - return () -> new TreeHeightCollapseStrategy(node); + return () -> new HeightCollapseStrategy("0"); } } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/style/HasWaveEffect.java b/domino-ui/src/main/java/org/dominokit/domino/ui/style/HasWaveEffect.java index c534224bc..c97789fa9 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/style/HasWaveEffect.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/style/HasWaveEffect.java @@ -24,21 +24,6 @@ */ public interface HasWaveEffect { - /** - * Initializes the wave effect on the implementing object. - * - * @return the current instance of the implementing object for method chaining - */ - T initWaves(); - - /** - * Sets the style of the wave effect on the implementing object. - * - * @param type the desired style of the wave effect - * @return the current instance of the implementing object for method chaining - */ - T setWaveStyle(WaveStyle type); - /** * Removes the wave effect from the implementing object. * diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/style/WaveStyle.java b/domino-ui/src/main/java/org/dominokit/domino/ui/style/WaveStyle.java deleted file mode 100644 index ee06250f5..000000000 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/style/WaveStyle.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.style; - -/** - * Enum representing various styles for the Waves (ripple) effect. - * - *

This enumeration allows easy definition and use of different visual styles for the Waves - * effect in the UI. - * - *

Usage Example: - * - *

- * element.addCss(WaveStyle.CIRCLE);
- * 
- */ -public enum WaveStyle implements HasCssClass { - - /** Represents a floating wave effect. */ - FLOAT(() -> "dui-waves-float"), - - /** Represents a circular wave effect. */ - CIRCLE(() -> "dui-waves-circle"), - - /** Represents a ripple wave effect. */ - RIPPLE(() -> "dui-waves-ripple"), - - /** Represents a block wave effect. */ - BLOCK(() -> "dui-waves-block"); - - private final CssClass style; - - /** - * Private constructor for defining a specific wave style. - * - * @param style the CSS class associated with the wave style. - */ - WaveStyle(CssClass style) { - this.style = style; - } - - /** - * Retrieves the CSS class associated with the specific wave style. - * - * @return the {@link CssClass} representing the wave style. - */ - @Override - public CssClass getCssClass() { - return style; - } -} diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/style/Waves.java b/domino-ui/src/main/java/org/dominokit/domino/ui/style/Waves.java index 27cad6e65..4bded6d37 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/style/Waves.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/style/Waves.java @@ -15,23 +15,13 @@ */ package org.dominokit.domino.ui.style; -import static elemental2.dom.DomGlobal.window; -import static java.util.Objects.nonNull; -import static org.dominokit.domino.ui.events.EventType.mousedown; import static org.dominokit.domino.ui.utils.ElementsFactory.elements; +import static org.dominokit.domino.ui.utils.Unit.px; -import elemental2.dom.DOMRect; -import elemental2.dom.DomGlobal; -import elemental2.dom.Element; -import elemental2.dom.Event; -import elemental2.dom.EventListener; -import elemental2.dom.MouseEvent; +import elemental2.dom.*; import jsinterop.base.Js; -import jsinterop.base.JsPropertyMap; import org.dominokit.domino.ui.IsElement; -import org.dominokit.domino.ui.elements.DivElement; import org.dominokit.domino.ui.utils.DominoElement; -import org.gwtproject.timer.client.Timer; /** * Provides a ripple (or "wave") effect on a given DOM element. @@ -40,13 +30,11 @@ */ public class Waves implements IsElement { - private final DivElement target; - DivElement ripple; - private JsPropertyMap rippleStyle; - private Timer delayTimer; - private Timer removeTimer; - private final int duration = 750; - private final WavesEventListener wavesEventListener = new WavesEventListener(); + public static final CssClass dui_ripple_wave = () -> "dui-ripple-wave"; + public static final CssClass dui_ripple_wave_active = () -> "dui-ripple-wave-active"; + + private final DominoElement target; + private EventListener waveListener; /** * Constructs a wave effect wrapper for a given target. @@ -66,8 +54,41 @@ public Waves(Element target) { * @param target The {@link DominoElement} on which the ripple effect will be applied. */ public Waves(DominoElement target) { - this.target = elements.div().addCss("dui-wave-sentinel"); - elements.elementOf(target).addCss("dui-waves-target").appendChild(this.target); + this.target = target; + target.addCss(dui_ripple_wave); + waveListener = + evt -> { + if (target.isEnabled()) { + MouseEvent e = Js.uncheckedCast(evt); + DOMRect rect = target.getBoundingClientRect(); + // Determine the maximum dimension for full coverage + double size = Math.max(rect.width, rect.height); + // Calculate coordinates so that the ripple centers on the click position + double x = e.clientX - rect.left - size / 2; + double y = e.clientY - rect.top - size / 2; + + // Set CSS custom properties for the pseudo-element + target.setCssProperty("--dui-ripple-x", px.of(x)); + target.setCssProperty("--dui-ripple-y", px.of(y)); + target.setCssProperty("--dui-ripple-size", px.of(size)); + + // Add the class to trigger the ripple animation + target.addCss(dui_ripple_wave_active); + + AddEventListenerOptions addEventListenerOptions = AddEventListenerOptions.create(); + addEventListenerOptions.setOnce(true); + // Remove the class after animation completes so it can be triggered again + target + .element() + .addEventListener( + "animationend", + event -> { + target.removeCss(dui_ripple_wave_active); + }, + addEventListenerOptions); + } + }; + target.addClickListener(waveListener); } /** @@ -93,13 +114,6 @@ public static Waves create(DominoElement target) { return new Waves(target); } - /** Initializes the wave effect on the target. */ - public void initWaves() { - if (isTargetDisabled()) return; - - target.addEventListener(mousedown.getName(), wavesEventListener); - } - /** * Removes the wave (ripple) effect from the target element. * @@ -107,127 +121,13 @@ public void initWaves() { * sentinel div (used for the ripple effect) from the DOM. */ public void removeWaves() { - target.removeEventListener(mousedown.getName(), wavesEventListener); - this.target.remove(); - } - - private boolean isTargetDisabled() { - return target.getAttribute("disabled") != null || target.style().containsCss("disabled"); - } - - private void setupStopTimers() { - delayTimer = - new Timer() { - @Override - public void run() { - rippleStyle.set("opacity ", "0"); - - ripple.setAttribute("style", convertStyle(rippleStyle)); - - removeTimer = - new Timer() { - @Override - public void run() { - ripple.removeCss("dui-waves-rippling"); - ripple.remove(); - } - }; - removeTimer.schedule(duration); - } - }; - - delayTimer.schedule(300); - } - - private void stopCurrentWave() { - if (nonNull(delayTimer)) delayTimer.cancel(); - if (nonNull(removeTimer)) removeTimer.cancel(); - if (nonNull(ripple)) { - final DivElement temp = ripple; - DomGlobal.setTimeout(p -> temp.remove(), 100); - } - } - - private String convertStyle(JsPropertyMap rippleStyle) { - StringBuilder style = new StringBuilder(); - rippleStyle.forEach( - key -> style.append(key).append(":").append(rippleStyle.get(key)).append(";")); - - return style.toString(); + dui_ripple_wave_active.remove(this.target); + dui_ripple_wave.remove(target); + this.target.removeEventListener("click", waveListener); } - /** {@inheritDoc} */ @Override public Element element() { - return target.element(); - } - - private ElementOffset offset(Element target) { - Element docElem = target.ownerDocument.documentElement; - DOMRect box = target.getBoundingClientRect(); - ElementOffset position = new ElementOffset(); - position.top = box.top + window.pageYOffset - docElem.clientTop; - position.left = box.left + window.pageXOffset - docElem.clientLeft; - return position; - } - - private static class ElementOffset { - private double top = 0; - private double left = 0; - } - - /** Represents an event listener to trigger and manage the wave effect on the target. */ - private final class WavesEventListener implements EventListener { - - @Override - public void handleEvent(Event evt) { - MouseEvent mouseEvent = Js.cast(evt); - if (mouseEvent.button == 2) { - return; - } - - stopCurrentWave(); - - ripple = elements.div().addCss("dui-waves-ripple", "dui-waves-rippling"); - target.appendChild(ripple); - ElementOffset position = offset(target.element()); - double relativeY = (mouseEvent.pageY - position.top); - double relativeX = (mouseEvent.pageX - position.left); - - relativeY = relativeY >= 0 ? relativeY : 0; - relativeX = relativeX >= 0 ? relativeX : 0; - - int clientWidth = target.element().clientWidth; - - double scaleValue = (clientWidth * 0.01) * 3; - String scale = "scale(" + scaleValue + ")"; - String translate = "translate(0,0)"; - - rippleStyle = Js.cast(JsPropertyMap.of()); - - rippleStyle.set("top", relativeY + "px"); - rippleStyle.set("left", relativeX + "px"); - ripple.addCss("dui-waves-notransition"); - - ripple.setAttribute("style", convertStyle(rippleStyle)); - - ripple.removeCss("dui-waves-notransition"); - - rippleStyle.set("-webkit-transform", scale + " " + translate); - rippleStyle.set("-moz-transform", scale + " " + translate); - rippleStyle.set("-ms-transform", scale + " " + translate); - rippleStyle.set("-o-transform", scale + " " + translate); - rippleStyle.set("transform", scale + " " + translate); - rippleStyle.set("opacity ", "1"); - - rippleStyle.set("-webkit-transition-duration", duration + "ms"); - rippleStyle.set("-moz-transition-duration", duration + "ms"); - rippleStyle.set("-o-transition-duration", duration + "ms"); - rippleStyle.set("transition-duration", duration + "ms"); - - ripple.setAttribute("style", convertStyle(rippleStyle)); - - setupStopTimers(); - } + return this.target.element(); } } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/style/WavesElement.java b/domino-ui/src/main/java/org/dominokit/domino/ui/style/WavesElement.java index 4b8be5793..45c16b275 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/style/WavesElement.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/style/WavesElement.java @@ -15,8 +15,6 @@ */ package org.dominokit.domino.ui.style; -import static org.dominokit.domino.ui.utils.Domino.*; - import elemental2.dom.HTMLElement; import org.dominokit.domino.ui.IsElement; import org.dominokit.domino.ui.utils.BaseDominoElement; @@ -57,17 +55,6 @@ public void init(T element) { wavesSupport = WavesSupport.addFor(this.getWavesElement()); } - /** - * Initializes the Waves (ripple) effect on this element. - * - * @return the current instance for chaining - */ - @Override - public T initWaves() { - wavesSupport.initWaves(); - return element; - } - /** * Removes the Waves (ripple) effect from this element. * diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/style/WavesSupport.java b/domino-ui/src/main/java/org/dominokit/domino/ui/style/WavesSupport.java index 42155bb89..d07012ba8 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/style/WavesSupport.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/style/WavesSupport.java @@ -16,7 +16,6 @@ package org.dominokit.domino.ui.style; import static org.dominokit.domino.ui.utils.Domino.*; -import static org.dominokit.domino.ui.utils.ElementsFactory.elements; import elemental2.dom.Element; import org.dominokit.domino.ui.utils.DominoElement; @@ -38,10 +37,7 @@ */ public class WavesSupport implements HasWaveEffect { - private static final CssClass dui_waves_effect = () -> "dui-waves-effect"; - private final DominoElement element; private final Waves wavesElement; - private final SwapCssClass waveClass = SwapCssClass.of(WaveStyle.RIPPLE); /** * Private constructor for initializing WavesSupport with a {@link HasWavesElement}. @@ -58,8 +54,7 @@ private WavesSupport(HasWavesElement targetElement) { * @param targetElement target DOM element. */ private WavesSupport(Element targetElement) { - this.element = elements.elementOf(targetElement); - wavesElement = Waves.create(this.element); + wavesElement = Waves.create(targetElement); } /** @@ -69,7 +64,7 @@ private WavesSupport(Element targetElement) { * @return an instance of {@link WavesSupport}. */ public static WavesSupport addFor(HasWavesElement element) { - return new WavesSupport(element).initWaves(); + return new WavesSupport(element); } /** @@ -79,40 +74,11 @@ public static WavesSupport addFor(HasWavesElement element) { * @return an instance of {@link WavesSupport}. */ public static WavesSupport addFor(Element element) { - return new WavesSupport(element).initWaves(); - } - - /** - * Initializes the Waves (ripple) effect on the element. - * - * @return the current instance of {@link WavesSupport} for chaining. - */ - @Override - public WavesSupport initWaves() { - if (!hasWavesEffect()) { - element.addCss(dui_waves_effect); - wavesElement.initWaves(); - } - return this; + return new WavesSupport(element); } private boolean hasWavesEffect() { - return dui_waves_effect.isAppliedTo(element); - } - - /** - * Sets the style of the Waves (ripple) effect on the element. - * - * @param waveStyle the desired {@link WaveStyle}. - * @return the current instance of {@link WavesSupport} for chaining. - */ - @Override - public WavesSupport setWaveStyle(WaveStyle waveStyle) { - if (!hasWavesEffect()) { - initWaves(); - } - element.addCss(waveClass.replaceWith(waveStyle)); - return this; + return Waves.dui_ripple_wave.isAppliedTo(wavesElement.element()); } /** @@ -122,26 +88,16 @@ public WavesSupport setWaveStyle(WaveStyle waveStyle) { */ @Override public WavesSupport removeWaves() { - dui_waves_effect.remove(element); - waveClass.remove(element); - removeWaveStyles(); wavesElement.removeWaves(); return this; } - private void removeWaveStyles() { - for (int i = 0; i < element.style().cssClassesCount(); ++i) { - String style = element.style().cssClassByIndex(i); - if (style.contains("waves-")) element.removeCss(style); - } - } - /** * Gets the {@link DominoElement} associated with this WavesSupport. * * @return the {@link DominoElement} instance. */ public DominoElement getElement() { - return element; + return elementOf(wavesElement.element()); } } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/tree/TreeNode.java b/domino-ui/src/main/java/org/dominokit/domino/ui/tree/TreeNode.java index 06aef086b..e8200eceb 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/tree/TreeNode.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/tree/TreeNode.java @@ -46,7 +46,6 @@ import org.dominokit.domino.ui.icons.Icon; import org.dominokit.domino.ui.icons.StateChangeIcon; import org.dominokit.domino.ui.icons.ToggleIcon; -import org.dominokit.domino.ui.style.WaveStyle; import org.dominokit.domino.ui.utils.BaseDominoElement; import org.dominokit.domino.ui.utils.HasSelectionListeners; import org.dominokit.domino.ui.utils.LazyChild; @@ -152,13 +151,13 @@ private TreeNode() { a().removeHref() .addCss(dui_tree_anchor) .appendChild(contentElement = div().addCss(dui_tree_item_content))) - .appendChild(subTree = ul().addCss(dui_tree_nav).hide()); + .appendChild(subTree = ul().addCss(dui_tree_nav).setHeight("0px")); this.textElement = LazyChild.of(span().addCss(dui_tree_item_text), contentElement); init((N) this); // default collapsible strategy setCollapseStrategy(getConfig().getTreeDefaultCollapseStrategy(this).get()); - setAttribute(Collapsible.DUI_COLLAPSED, "true"); + subTree.setAttribute(Collapsible.DUI_COLLAPSED, "true"); } /** @@ -174,6 +173,11 @@ public TreeNode(Icon icon, String title) { init(); } + @Override + public Collapsible getCollapsible() { + return this.subTree.getCollapsible(); + } + /** * Constructs a new {@code TreeNode} with a title only (no icon). * @@ -623,7 +627,7 @@ public boolean isLeaf() { * needed. */ protected void applyWaves() { - withWaves((item, waves) -> waves.setWaveStyle(WaveStyle.BLOCK)); + withWaves(); } /** 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 813498dbb..6d4edbb15 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 @@ -59,7 +59,6 @@ import org.dominokit.domino.ui.style.HasCssClass; import org.dominokit.domino.ui.style.HasCssClasses; import org.dominokit.domino.ui.style.Style; -import org.dominokit.domino.ui.style.WaveStyle; import org.dominokit.domino.ui.style.WavesSupport; import org.dominokit.domino.ui.themes.DominoThemeManager; import org.gwtproject.editor.client.Editor; @@ -2596,17 +2595,6 @@ public T withWaves(WavesStyler wavesStyler) { return element; } - /** - * Sets the wave style for this element's Waves effect. - * - * @param waveStyle The wave style to set. - * @return The modified DOM element. - */ - public T setWaveStyle(WaveStyle waveStyle) { - wavesSupport.setWaveStyle(waveStyle); - return element; - } - /** * Applies the given element handler to this element. * diff --git a/domino-ui/src/main/resources/org/dominokit/domino/ui/public/css/domino-ui/dui-components/domino-ui-collapse.css b/domino-ui/src/main/resources/org/dominokit/domino/ui/public/css/domino-ui/dui-components/domino-ui-collapse.css index 1f4e8677c..cfd161c0c 100644 --- a/domino-ui/src/main/resources/org/dominokit/domino/ui/public/css/domino-ui/dui-components/domino-ui-collapse.css +++ b/domino-ui/src/main/resources/org/dominokit/domino/ui/public/css/domino-ui/dui-components/domino-ui-collapse.css @@ -191,6 +191,14 @@ transition: height 1000ms, padding-top 1000ms, padding-bottom 1000ms, margin-top 1000ms, margin-bottom 1000ms; } +.dui-height-collapsed-trans-2000 { + transition: height 2000ms, padding-top 2000ms, padding-bottom 2000ms, margin-top 2000ms, margin-bottom 2000ms; +} + +.dui-height-collapsed-trans-20000 { + transition: height 20000ms, padding-top 20000ms, padding-bottom 20000ms, margin-top 20000ms, margin-bottom 20000ms; +} + .dui.dui-height-collapsed[dui-collapsed='true'] { padding-top: 0 !important; padding-bottom: 0 !important; diff --git a/domino-ui/src/main/resources/org/dominokit/domino/ui/public/css/domino-ui/dui-components/domino-ui-waves.css b/domino-ui/src/main/resources/org/dominokit/domino/ui/public/css/domino-ui/dui-components/domino-ui-waves.css index 4932c0738..7b0845263 100644 --- a/domino-ui/src/main/resources/org/dominokit/domino/ui/public/css/domino-ui/dui-components/domino-ui-waves.css +++ b/domino-ui/src/main/resources/org/dominokit/domino/ui/public/css/domino-ui/dui-components/domino-ui-waves.css @@ -6,116 +6,39 @@ * Released under the MIT license * https://github.com/fians/Waves/blob/master/LICENSE */ -.dui-waves-target { +.dui-ripple-wave { position: relative; + overflow: hidden; } -.dui-waves-effect .dui-waves-ripple { +/* The pseudo-element that will show the ripple */ +.dui-ripple-wave::after { + content: ""; position: absolute; - border-radius: 50%; - width: 100px; - height: 100px; - margin-top: -50px; - margin-left: -50px; - opacity: 0; - background: var(--dui-wave-bg, var(--dui-bg-l-3, rgba(0, 0, 0, 0.3))); - -webkit-transition: all 100s ease-out; - -moz-transition: all 100s ease-out; - -o-transition: all 100s ease-out; - transition: all 100s ease-out; - -webkit-transition-property: -webkit-transform, opacity; - -moz-transition-property: -moz-transform, opacity; - -o-transition-property: -o-transform, opacity; - transition-property: transform, opacity; - -webkit-transform: scale(0) translate(0, 0); - -moz-transform: scale(0) translate(0, 0); - -ms-transform: scale(0) translate(0, 0); - -o-transform: scale(0) translate(0, 0); - transform: scale(0) translate(0, 0); -} -.dui-waves-effect.dui-waves-light .dui-waves-ripple { - background: rgba(255, 255, 255, 0.4); - background: -webkit-radial-gradient(rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70%); - background: -o-radial-gradient(rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70%); - background: -moz-radial-gradient(rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70%); - background: radial-gradient(rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70%); -} -.dui-waves-effect.dui-waves-classic .dui-waves-ripple { - /*background: rgba(0, 0, 0, 0.2);*/ + left: var(--dui-ripple-x, 0); + top: var(--dui-ripple-y, 0); + width: var(--dui-ripple-size, 100px); + height: var(--dui-ripple-size, 100px); background: var(--dui-wave-bg, var(--dui-bg-l-3, rgba(0, 0, 0, 0.2))); -} -.dui-waves-effect.dui-waves-classic.dui-waves-light .dui-waves-ripple { - background:var(--dui-wave-bg, rgba(255, 255, 255, 0.4)); -} -.dui-waves-notransition { - -webkit-transition: none !important; - -moz-transition: none !important; - -o-transition: none !important; - transition: none !important; -} -.dui-waves-button, -.dui-waves-circle { - -webkit-transform: translateZ(0); - -moz-transform: translateZ(0); - -ms-transform: translateZ(0); - -o-transform: translateZ(0); - transform: translateZ(0); - -webkit-mask-image: -webkit-radial-gradient(circle, #ffffff 100%, #000000 100%); -} -.dui-waves-button, -.dui-waves-button:hover, -.dui-waves-button:visited, -.dui-waves-button-input { - white-space: nowrap; - vertical-align: middle; - cursor: pointer; - border: none; - outline: none; - color: inherit; - background-color: rgba(0, 0, 0, 0); - font-size: 1em; - line-height: 1em; - text-align: center; - text-decoration: none; - z-index: 1; -} -.dui-waves-button { - padding: 0.85em 1.1em; - border-radius: 0.2em; -} -.dui-waves-button-input { - margin: 0; - padding: 0.85em 1.1em; -} -.dui-waves-input-wrapper { - border-radius: 0.2em; - vertical-align: bottom; -} -.dui-waves-input-wrapper.dui-waves-button { - padding: 0; -} -.dui-waves-input-wrapper .dui-waves-button-input { - position: relative; - top: 0; - left: 0; - z-index: 1; + opacity: 1; + border-radius: 50%; + transform: scale(0); } -.dui-waves-float { - -webkit-mask-image: none; - -webkit-box-shadow: 0px 1px 1.5px 1px rgba(0, 0, 0, 0.12); - box-shadow: 0px 1px 1.5px 1px rgba(0, 0, 0, 0.12); - -webkit-transition: all 300ms; - -moz-transition: all 300ms; - -o-transition: all 300ms; - transition: all 300ms; +/* When the ripple is active, trigger the animation on the pseudo-element */ +.dui-ripple-wave.dui-ripple-wave-active::after { + animation: ripple-animation 600ms linear; } -.dui-waves-float:active { - -webkit-box-shadow: 0px 8px 20px 1px rgba(0, 0, 0, 0.3); - box-shadow: 0px 8px 20px 1px rgba(0, 0, 0, 0.3); -} -.dui-waves-block { - display: block; + +@keyframes ripple-animation { + from { + transform: scale(0); + opacity: 0.7; + } + to { + transform: scale(4); + opacity: 0; + } } .dui.dui-waves-primary { @@ -232,4 +155,4 @@ .dui.dui-waves-black { --dui-wave-bg:var(--dui-clr-black); -} \ No newline at end of file +}