Skip to content

Commit

Permalink
fix #931, #686 Support different behaviors for tabs over flow
Browse files Browse the repository at this point in the history
  • Loading branch information
vegegoku committed Sep 24, 2024
1 parent f049d19 commit 7809fb4
Show file tree
Hide file tree
Showing 11 changed files with 681 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.function.Supplier;
import org.dominokit.domino.ui.icons.Icon;
import org.dominokit.domino.ui.icons.lib.Icons;
import org.dominokit.domino.ui.tabs.TabsOverflow;

/**
* Implementations of this interface can be used to configure defaults for {@link
Expand All @@ -35,4 +36,14 @@ public interface TabsConfig extends ComponentConfig {
default Supplier<Icon<?>> getDefaultTabCloseIcon() {
return Icons::close;
}

/**
* Use this method to implement the default Tabs overflow behavior. check {@link TabsOverflow} to
* see available behaviors, default to {@link TabsOverflow#WRAP}
*
* @return TabsOverflow behavior.
*/
default TabsOverflow getTabsDefaultOverflowHandler() {
return TabsOverflow.WRAP;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
* 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.tabs;

import static org.dominokit.domino.ui.style.DisplayCss.dui_overflow_hidden;
import static org.dominokit.domino.ui.style.GenericCss.dui_vertical;

import elemental2.dom.DOMRect;
import elemental2.dom.Element;
import java.util.function.Consumer;
import org.dominokit.domino.ui.elements.UListElement;
import org.dominokit.domino.ui.icons.MdiIcon;
import org.dominokit.domino.ui.icons.lib.Icons;
import org.dominokit.domino.ui.utils.BaseDominoElement;
import org.gwtproject.timer.client.Timer;

public class ScrollTabsHandler implements TabsOverflowHandler {

private MdiIcon scrollLeftIcon;
private MdiIcon scrollRightIcon;
private Timer timer;
private Consumer<Tab> closeHandler;
private final BaseDominoElement.HandlerRecord resizeRecord =
new BaseDominoElement.HandlerRecord();

public ScrollTabsHandler() {
scrollLeftIcon = Icons.menu_left().clickable();
scrollRightIcon = Icons.menu_right().clickable();
}

@Override
public void apply(TabsPanel tabsPanel) {
tabsPanel.withTabsNav(
(panel, nav) -> {
nav.addCss(dui_overflow_hidden);
scrollLeftIcon.addClickListener(
evt -> {
if (dui_vertical.isAppliedTo(panel)) {
double shift = nav.getBoundingClientRect().height / 2;
nav.element().scrollTop = nav.element().scrollTop - shift;
} else {
double shift = nav.getBoundingClientRect().width / 2;
nav.element().scrollLeft = nav.element().scrollLeft - shift;
}
});
scrollRightIcon.addClickListener(
evt -> {
if (dui_vertical.isAppliedTo(panel)) {
double shift = nav.getBoundingClientRect().height / 2;
nav.element().scrollTop = nav.element().scrollTop + shift;
} else {
double shift = nav.getBoundingClientRect().width / 2;
nav.element().scrollLeft = nav.element().scrollLeft + shift;
}
});

tabsPanel.addCloseHandler(
closeHandler =
tab -> {
updateTabs(tabsPanel, nav);
});
nav.nowOrWhenAttached(
() -> {
updateTabs(tabsPanel, nav);
timer =
new Timer() {
@Override
public void run() {
updateTabs(panel, nav);
}
};

nav.onResize(
(element, observer, entries) -> {
timer.schedule(250);
},
resizeRecord);
});
if (dui_vertical.isAppliedTo(tabsPanel)) {
scrollLeftIcon.rotate90();
scrollRightIcon.rotate90();
}
});
}

@Override
public void update(TabsPanel tabsPanel) {
tabsPanel.withTabsNav(
(panel, nav) -> {
updateTabs(tabsPanel, nav);
});
}

private void updateTabs(TabsPanel tabsPanel, UListElement nav) {
if (isOverFlowing(nav.element())) {
tabsPanel.getLeadingNav().appendChild(scrollLeftIcon);
tabsPanel.getTailNav().appendChild(scrollRightIcon);

tabsPanel.getTabs().stream()
.filter(tab -> isPartialVisible(nav.element(), tab.element()) && tab.isActive())
.findFirst()
.ifPresent(
tab -> {
if (dui_vertical.isAppliedTo(tabsPanel)) {
DOMRect parentRect = nav.getBoundingClientRect();
DOMRect childRect = tab.getBoundingClientRect();

double shift = childRect.top - parentRect.top;
nav.element().scrollTop = nav.element().scrollTop + shift;
} else {
DOMRect parentRect = nav.getBoundingClientRect();
DOMRect childRect = tab.getBoundingClientRect();

double shift = childRect.right - parentRect.right;
nav.element().scrollLeft = nav.element().scrollLeft + shift;
}
});
} else {
scrollLeftIcon.remove();
scrollRightIcon.remove();
}
}

@Override
public void cleanUp(TabsPanel tabsPanel) {
scrollLeftIcon.remove();
scrollRightIcon.remove();
tabsPanel.removeCloseHandler(closeHandler);
timer.cancel();
resizeRecord.remove();
}

private boolean isOverFlowing(Element element) {
return element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight;
}

private boolean isPartialVisible(Element parent, Element child) {
DOMRect parentRect = parent.getBoundingClientRect();
DOMRect childRect = child.getBoundingClientRect();

boolean fullyVisible =
childRect.left >= parentRect.left
&& childRect.right <= parentRect.right
&& childRect.top >= parentRect.top
&& childRect.bottom <= parentRect.bottom;

return !fullyVisible;
}
}
4 changes: 4 additions & 0 deletions domino-ui/src/main/java/org/dominokit/domino/ui/tabs/Tab.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.dominokit.domino.ui.tabs;

import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static org.dominokit.domino.ui.utils.Domino.*;

Expand Down Expand Up @@ -409,6 +410,9 @@ public Tab setClosable(boolean closable) {
* @return The current {@link Tab} instance.
*/
public Tab close() {
if (isNull(parent)) {
DomGlobal.console.info("Parent is null.");
}
if (nonNull(parent)) {
closeCondition.onBeforeClose(
this,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

public interface TabStyles {
CssClass dui_tabs_nav = () -> "dui-tabs-nav";
CssClass dui_tabs_main_nav = () -> "dui-tabs-main-nav";
CssClass dui_tabs_leading_nav = () -> "dui-tabs-leading-nav";
CssClass dui_tabs_tail_nav = () -> "dui-tabs-tail-nav";
CssClass dui_tab_item = () -> "dui-tab-item";
CssClass dui_tab_anchor = () -> "dui-tab-anchor";
CssClass dui_tabs = () -> "dui-tabs";
Expand Down
Loading

0 comments on commit 7809fb4

Please sign in to comment.