Skip to content

Commit

Permalink
Improve ListMenu jmix-framework#2667
Browse files Browse the repository at this point in the history
  • Loading branch information
yuriy-khrebtov authored Dec 28, 2023
1 parent bbdc66e commit cb82697
Show file tree
Hide file tree
Showing 9 changed files with 300 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.google.common.base.Strings;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Composite;
import com.vaadin.flow.component.HasComponents;
import com.vaadin.flow.component.HasSize;
import com.vaadin.flow.component.HasStyle;
import com.vaadin.flow.component.Key;
Expand All @@ -33,6 +34,7 @@
import com.vaadin.flow.component.html.UnorderedList;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.shared.HasThemeVariant;
import com.vaadin.flow.router.HighlightConditions;
import com.vaadin.flow.router.RouterLink;
import io.jmix.flowui.kit.component.KeyCombination;
Expand All @@ -51,7 +53,7 @@
import java.util.Map;
import java.util.function.Consumer;

public class ListMenu extends Composite<UnorderedList> implements HasSize, HasStyle {
public class ListMenu extends Composite<UnorderedList> implements HasSize, HasStyle, HasThemeVariant<ListMenuVariant> {

protected static final String TEXT_SMALL_CLASS_NAME = "text-s";
protected static final String LIST_NONE_CLASS_NAME = "list-none";
Expand All @@ -71,6 +73,8 @@ public class ListMenu extends Composite<UnorderedList> implements HasSize, HasSt
protected static final String JMIX_MENU_ITEM_LINK_CLASS_NAME = "jmix-menu-item-link";
protected static final String LINK_ICON_CLASS_NAME = "link-icon";
protected static final String LINK_TEXT_CLASS_NAME = "link-text";
protected static final String PREFIX_COMPONENT_CLASS_NAME = "prefix-component";
protected static final String SUFFIX_COMPONENT_CLASS_NAME = "suffix-component";

protected List<MenuItem> rootMenuItems = new ArrayList<>();

Expand Down Expand Up @@ -300,7 +304,10 @@ protected RouterLink createMenuItemComponent(MenuItem menuItem) {
routerLink.addClassNames(menuItem.getClassNames().toArray(new String[0]));
routerLink.setHighlightCondition(HighlightConditions.never());

if (menuItem.getIcon() != null) {
Component prefixComponent = menuItem.getPrefixComponent();
if (prefixComponent != null) {
setPrefixComponent(routerLink, prefixComponent, null);
} else if (menuItem.getIcon() != null) {
Icon icon = new Icon(menuItem.getIcon());
icon.addClassName(LINK_ICON_CLASS_NAME);
routerLink.add(icon);
Expand All @@ -314,6 +321,7 @@ protected RouterLink createMenuItemComponent(MenuItem menuItem) {
addMenuItemClickShortcutCombination(routerLink, menuItem);

routerLink.add(text);
setSuffixComponent(routerLink, menuItem.getSuffixComponent(), null);

return routerLink;
}
Expand Down Expand Up @@ -348,26 +356,28 @@ protected Details createMenuBarComponent(MenuBarItem menuBarItem) {
menuItemComponent.addClassNames(menuBarItem.getClassNames().toArray(new String[0]));
menuItemComponent.setOpened(menuBarItem.isOpened());

Div div = new Div();
div.setWidthFull();
div.addClassName(JMIX_MENUBAR_SUMMARY_ICON_CONTAINER_CLASS_NAME);
div.setTitle(Strings.nullToEmpty(menuBarItem.getDescription()));

Component prefixComponent = menuBarItem.getPrefixComponent();
if (prefixComponent != null) {
setPrefixComponent(div, prefixComponent, null);
} else if (menuBarItem.getIcon() != null) {
Icon icon = new Icon(menuBarItem.getIcon());
icon.addClassName(MENUBAR_ICON_CLASS_NAME);
div.add(icon);
}

Span summary = new Span();
summary.setText(getTitle(menuBarItem));
summary.addClassNames(MENUBAR_SUMMARY_CLASS_NAME, TEXT_SMALL_CLASS_NAME);
div.add(summary);

Icon icon = null;
if (menuBarItem.getIcon() != null) {
icon = new Icon(menuBarItem.getIcon());
icon.addClassName(MENUBAR_ICON_CLASS_NAME);
}
setSuffixComponent(div, menuBarItem.getSuffixComponent(), null);

if (icon != null) {
Div div = new Div();
div.add(icon, summary);
div.addClassName(JMIX_MENUBAR_SUMMARY_ICON_CONTAINER_CLASS_NAME);
div.setTitle(Strings.nullToEmpty(menuBarItem.getDescription()));
menuItemComponent.setSummary(div);
} else {
summary.setTitle(Strings.nullToEmpty(menuBarItem.getDescription()));
menuItemComponent.setSummary(summary);
}
menuItemComponent.setSummary(div);

UnorderedList menuList = new UnorderedList();
menuList.addClassNames(MENUBAR_LIST_CLASS_NAME, LIST_NONE_CLASS_NAME, MARGIN_NONE_CLASS_NAME,
Expand Down Expand Up @@ -424,6 +434,34 @@ protected void checkItemIdDuplicate(String id) {
}
}

protected void setPrefixComponent(HasComponents componentContainer,
@Nullable Component prefixComponent,
@Nullable Component oldPrefixComponent) {
if (oldPrefixComponent != null) {
oldPrefixComponent.removeClassName(PREFIX_COMPONENT_CLASS_NAME);
componentContainer.remove(oldPrefixComponent);
}

if (prefixComponent != null) {
prefixComponent.addClassName(PREFIX_COMPONENT_CLASS_NAME);
componentContainer.addComponentAsFirst(prefixComponent);
}
}

protected void setSuffixComponent(HasComponents componentContainer,
@Nullable Component suffixComponent,
@Nullable Component oldSuffixComponent) {
if (oldSuffixComponent != null) {
oldSuffixComponent.removeClassName(SUFFIX_COMPONENT_CLASS_NAME);
componentContainer.remove(oldSuffixComponent);
}

if (suffixComponent != null) {
suffixComponent.addClassName(SUFFIX_COMPONENT_CLASS_NAME);
componentContainer.add(suffixComponent);
}
}

protected void onMenuItemPropertyChange(PropertyChangeEvent event) {
if (MenuBarItem.MENU_ITEM_OPENED.equals(event.getPropertyName())) {
Details menuBarComponent = getMenuBarComponent((MenuItem) event.getSource());
Expand All @@ -441,13 +479,43 @@ protected void onMenuItemPropertyChange(PropertyChangeEvent event) {
menuItemComponent.addClassNames(menuItem.getClassNames().toArray(new String[0]));
}
}
if (MenuItem.MENU_ITEM_SUFFIX_COMPONENT.equals(event.getPropertyName())) {
MenuItem menuItem = (MenuItem) event.getSource();
Component oldSuffixComponent = (Component) event.getOldValue();
Component suffixComponent = (Component) event.getNewValue();

if (menuItem.isMenu()) {
Details menuBarComponent = getMenuBarComponent(menuItem);
Div summary = (Div) menuBarComponent.getSummary();
setSuffixComponent(summary, suffixComponent, oldSuffixComponent);
} else if (!menuItem.isSeparator()) {
RouterLink menuItemComponent = getMenuItemComponent(menuItem);
setSuffixComponent(menuItemComponent, suffixComponent, oldSuffixComponent);
}
}
if (MenuItem.MENU_ITEM_PREFIX_COMPONENT.equals(event.getPropertyName())) {
MenuItem menuItem = (MenuItem) event.getSource();
Component oldPrefixComponent = (Component) event.getOldValue();
Component prefixComponent = (Component) event.getNewValue();

if (menuItem.isMenu()) {
Details menuBarComponent = getMenuBarComponent(menuItem);
Div summary = (Div) menuBarComponent.getSummary();
setPrefixComponent(summary, prefixComponent, oldPrefixComponent);
} else if (!menuItem.isSeparator()) {
RouterLink menuItemComponent = getMenuItemComponent(menuItem);
setPrefixComponent(menuItemComponent, prefixComponent, oldPrefixComponent);
}
}
}

/**
* Describes menu item.
*/
public static class MenuItem implements io.jmix.flowui.kit.component.menu.MenuItem {
protected static final String MENU_ITEM_CLASS_NAME = "className";
protected static final String MENU_ITEM_PREFIX_COMPONENT = "prefixComponent";
protected static final String MENU_ITEM_SUFFIX_COMPONENT = "suffixComponent";

protected String id;
protected String title;
Expand All @@ -456,6 +524,8 @@ public static class MenuItem implements io.jmix.flowui.kit.component.menu.MenuIt
protected List<String> classNames;
protected Consumer<MenuItem> clickHandler;
protected KeyCombination shortcutCombination;
protected Component prefixComponent;
protected Component suffixComponent;

protected ListMenu menuComponent;

Expand Down Expand Up @@ -530,8 +600,10 @@ public MenuItem withDescription(@Nullable String description) {

/**
* @return icon or {@code null} if not set
* @deprecated use {@link #getPrefixComponent()}
*/
@Nullable
@Deprecated(since="2.2", forRemoval=true)
public VaadinIcon getIcon() {
return icon;
}
Expand All @@ -541,7 +613,9 @@ public VaadinIcon getIcon() {
*
* @param icon icon to set
* @return current menu instance
* @deprecated use {@link #withPrefixComponent(Component)} or {@link #setPrefixComponent(Component)}
*/
@Deprecated(since="2.2", forRemoval=true)
public MenuItem withIcon(@Nullable VaadinIcon icon) {
this.icon = icon;
return this;
Expand Down Expand Up @@ -617,6 +691,69 @@ public MenuItem withShortcutCombination(@Nullable KeyCombination shortcutCombina
return this;
}

/**
* @return suffix component of the item
*/
@Nullable
public Component getSuffixComponent() {
return suffixComponent;
}

/**
* Sets suffix component of the item.
*
* @param suffixComponent component to set
* @return current menu item instance
*/
public MenuItem withSuffixComponent(@Nullable Component suffixComponent) {
setSuffixComponent(suffixComponent);
return this;
}

/**
* Sets suffix component of the item.
*
* @param suffixComponent component to set
*/
public void setSuffixComponent(@Nullable Component suffixComponent) {
Component oldSuffixComponent = this.suffixComponent;
this.suffixComponent = suffixComponent;

propertyChangeSupport.firePropertyChange(MENU_ITEM_SUFFIX_COMPONENT, oldSuffixComponent,
this.suffixComponent);
}

/**
* @return prefix component of the item
*/
public Component getPrefixComponent() {
return prefixComponent;
}

/**
* Sets prefix component of the item.
*
* @param prefixComponent component to set
* @return current menu item instance
*/
public MenuItem withPrefixComponent(Component prefixComponent) {
setPrefixComponent(prefixComponent);
return this;
}

/**
* Sets prefix component of the item.
*
* @param prefixComponent component to set
*/
public void setPrefixComponent(Component prefixComponent) {
Component oldPrefixComponent = this.prefixComponent;
this.prefixComponent = prefixComponent;

propertyChangeSupport.firePropertyChange(MENU_ITEM_PREFIX_COMPONENT, oldPrefixComponent,
this.prefixComponent);
}

/**
* @return {@code true} if menu item is {@link MenuBarItem} that contains other items,
* {@code false} otherwise
Expand Down Expand Up @@ -704,6 +841,7 @@ public MenuBarItem withDescription(@Nullable String description) {
}

@Override
@Deprecated(since="2.2", forRemoval=true)
public MenuBarItem withIcon(@Nullable VaadinIcon icon) {
return (MenuBarItem) super.withIcon(icon);
}
Expand All @@ -713,6 +851,16 @@ public MenuBarItem withClassNames(List<String> classNames) {
return (MenuBarItem) super.withClassNames(classNames);
}

@Override
public MenuBarItem withSuffixComponent(Component suffixComponent) {
return (MenuBarItem) super.withSuffixComponent(suffixComponent);
}

@Override
public MenuBarItem withPrefixComponent(Component prefixComponent) {
return (MenuBarItem) super.withPrefixComponent(prefixComponent);
}

/**
* @return {@code true} if menu bar item initially should open list of sub menu items,
* {@code false} otherwise
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2023 Haulmont.
*
* 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 io.jmix.flowui.kit.component.main;

import com.vaadin.flow.component.shared.ThemeVariant;

/**
* Set of theme variants applicable for the {@link ListMenu} component.
*/
public enum ListMenuVariant implements ThemeVariant {

/**
* Expand/collapse toggle mark will be placed in the end of parent menu item component
*/
TOGGLE_REVERSE("toggle-reverse");

private final String variant;

ListMenuVariant(String variant) {
this.variant = variant;
}

@Override
public String getVariantName() {
return variant;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public interface StudioMainViewComponents {
@StudioProperty(xmlAttribute = "metaClass", type = StudioPropertyType.ENTITY_NAME),
@StudioProperty(xmlAttribute = "minHeight", type = StudioPropertyType.SIZE),
@StudioProperty(xmlAttribute = "minWidth", type = StudioPropertyType.SIZE),
@StudioProperty(xmlAttribute = "themeNames", type = StudioPropertyType.VALUES_LIST,
options = {"toggle-reverse"}),
@StudioProperty(xmlAttribute = "visible", type = StudioPropertyType.BOOLEAN,
defaultValue = "true"),
@StudioProperty(xmlAttribute = "width", type = StudioPropertyType.SIZE)
Expand Down
Loading

0 comments on commit cb82697

Please sign in to comment.