Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<groupId>org.vaadin.addons.flowingcode</groupId>
<artifactId>grid-helpers</artifactId>
<version>2.1.1-SNAPSHOT</version>
<version>2.2.0-SNAPSHOT</version>
<name>Grid Helpers Add-on</name>
<description>Grid Helpers Add-on for Vaadin Flow</description>
<url>https://www.flowingcode.com/en/open-source/</url>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* #%L
* Grid Helpers Add-on
* %%
* Copyright (C) 2022 - 2024 Flowing Code
* Copyright (C) 2022 - 2026 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -26,18 +26,24 @@

package com.flowingcode.vaadin.addons.gridhelpers;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.ComponentUtil;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.contextmenu.MenuItem;
import com.vaadin.flow.component.contextmenu.SubMenu;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.Grid.Column;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.menubar.MenuBar;
import com.vaadin.flow.component.menubar.MenuBarVariant;
import com.vaadin.flow.dom.Style;
import com.vaadin.flow.dom.Style.AlignItems;
import com.vaadin.flow.shared.Registration;
import java.io.Serializable;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
Expand All @@ -48,13 +54,19 @@ class ColumnToggleHelper<T> implements Serializable {

private static final String GRID_HELPER_TOGGLE_THEME = "gridHelperToggle";

private static final String TOGGLE_ALIGN_ITEMS_PROPERTY = "--fc-grid-helper-toggle--align-items";

private static final String TOGGLE_CAPTION_DATA = GridHelper.class.getName() + "#TOGGLE_CAPTION";

private static final String HIDABLE_DATA = GridHelper.class.getName() + "#HIDABLE";

private final GridHelper<T> helper;

private Column<?> menuToggleColumn;
private MenuBar menuToggle;

private Component icon;

private String toggleLabel;

public void setColumnToggleVisible(boolean visible) {
// https://cookbook.vaadin.com/grid-column-toggle
Expand All @@ -66,35 +78,74 @@ public void setColumnToggleVisible(boolean visible) {
}

public boolean isColumnToggleVisible() {
return menuToggleColumn != null && menuToggleColumn.isVisible();
return menuToggle != null;
}

private Component getColumnToggleIcon() {
if (icon == null) {
icon = VaadinIcon.GRID_H.create();
}
return icon;
}

public void setColumnToggleIcon(Component icon) {
this.icon = Objects.requireNonNull(icon);
if (isColumnToggleVisible()) {
showColumnToggle();
}
}

public void setColumnToggleLabel(String label) {
this.toggleLabel = label;
if (isColumnToggleVisible()) {
showColumnToggle();
}
}

public void setColumnToggleAlignment(AlignItems alignment) {
// the custom property is set on the grid and inherited by the slotted menu bar,
// so that it survives the re-creation of the toggle
Style style = helper.getGrid().getStyle();
if (alignment == null) {
style.remove(TOGGLE_ALIGN_ITEMS_PROPERTY);
} else {
style.set(
TOGGLE_ALIGN_ITEMS_PROPERTY, alignment.name().replace('_', '-').toLowerCase(Locale.ROOT));
}
}

private void showColumnToggle() {
createMenuToggle()
.ifPresent(
toggle -> {
Grid<?> grid = helper.getGrid();
if (menuToggleColumn == null) {
menuToggleColumn = grid.addColumn(t -> "").setWidth("auto").setFlexGrow(0);
} else {
menuToggleColumn.setVisible(true);
}
grid.getHeaderRows().get(0).getCell(menuToggleColumn).setComponent(toggle);
removeMenuToggle();
menuToggle = toggle;
grid.getElement().appendChild(toggle.getElement());
});
}

private void hideColumnToggle() {
if (menuToggleColumn != null) {
menuToggleColumn.setVisible(false);
removeMenuToggle();
}

private void removeMenuToggle() {
if (menuToggle != null) {
menuToggle.getElement().removeFromParent();
menuToggle = null;
}
}

private Optional<MenuBar> createMenuToggle() {
Grid<T> grid = helper.getGrid();

MenuBar menuBar = new MenuBar();
menuBar.getThemeNames().add(MenuBarVariant.LUMO_TERTIARY.getVariantName());
menuBar.getThemeNames().add(MenuBarVariant.LUMO_TERTIARY_INLINE.getVariantName());
MenuItem menuItem = menuBar.addItem(VaadinIcon.ELLIPSIS_DOTS_V.create());
MenuItem menuItem = menuBar.addItem(getColumnToggleIcon());
if (toggleLabel != null) {
menuItem.add(new Span(toggleLabel));
}
SubMenu subMenu = menuItem.getSubMenu();

for (Column<T> column : grid.getColumns()) {
Expand All @@ -110,6 +161,7 @@ private Optional<MenuBar> createMenuToggle() {
}

menuBar.getThemeNames().add(GRID_HELPER_TOGGLE_THEME);
menuBar.getElement().setAttribute("slot", "fc-column-toggle");
return Optional.of(menuBar).filter(_menuBar -> !_menuBar.getItems().isEmpty());
}

Expand Down Expand Up @@ -170,7 +222,4 @@ public void setHidingToggleCaption(Column<?> column, String caption) {
}
}

Column<?> getMenuToggleColumn() {
return menuToggleColumn;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* #%L
* Grid Helpers Add-on
* %%
* Copyright (C) 2022 - 2025 Flowing Code
* Copyright (C) 2022 - 2026 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -38,19 +38,19 @@
import com.vaadin.flow.component.grid.HeaderRow;
import com.vaadin.flow.component.grid.HeaderRow.HeaderCell;
import com.vaadin.flow.component.grid.ItemClickEvent;
import com.vaadin.flow.component.icon.IconFactory;
import com.vaadin.flow.dom.Style;
import com.vaadin.flow.function.SerializableFunction;
import com.vaadin.flow.function.SerializablePredicate;
import com.vaadin.flow.shared.Registration;
import java.io.Serializable;
import java.util.Collection;
import java.util.Objects;
import lombok.AccessLevel;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@SuppressWarnings("serial")
@JsModule("./fcGridHelper/connector.js")
@CssImport(value = "./fcGridHelper/vaadin-menu-bar.css", themeFor = "vaadin-menu-bar")
@CssImport(value = GridHelper.GRID_STYLES, themeFor = "vaadin-grid")
@CssImport(
value = "./fcGridHelper/vaadin-context-menu-item.css",
Expand All @@ -67,10 +67,9 @@
@CssImport(
value = "./fcGridHelper/vaadin-checkbox.css",
themeFor = "vaadin-checkbox")
@CssImport(value = "./fcGridHelper/styles.css")
public final class GridHelper<T> implements Serializable {

private static final Logger logger = LoggerFactory.getLogger(GridHelper.class);

private static final String ARROW_SELECTION_PROPERTY = "_fcghArrowSelection";
private static final String ENHANCED_SELECTION_PROPERTY = "_fcghEnhancedSelection";

Expand Down Expand Up @@ -142,11 +141,6 @@
}
}

@SuppressWarnings("unchecked")
private static <T> GridHelper<T> getHelper(Column<T> column) {
return getHelper((Grid<T>) column.getGrid());
}

private static <T> GridHelper<T> getHelper(Grid<T> grid) {
@SuppressWarnings("unchecked")
GridHelper<T> helper = ComponentUtil.getData(grid, GridHelper.class);
Expand Down Expand Up @@ -309,6 +303,50 @@
return getHelper(grid).columnToggleHelper.isColumnToggleVisible();
}

/**
* Sets the icon of the menu that toggles the visibility of grid columns.
*
* @param grid the grid to be configured
* @param icon the component that is rendered in the column toggle
* @throws NullPointerException if {@code icon} is {@code null}
*/
public static void setColumnToggleIcon(Grid<?> grid, Component icon) {
getHelper(grid).columnToggleHelper.setColumnToggleIcon(icon);
}

/**
* Sets the icon of the menu that toggles the visibility of grid columns.
*
* @param grid the grid to be configured
* @param icon the factory of the icon that is rendered in the column toggle
* @throws NullPointerException if {@code icon} is {@code null}
*/
public static void setColumnToggleIcon(Grid<?> grid, IconFactory icon) {
setColumnToggleIcon(grid, icon.create());
}

/**
* Sets the text that is rendered next to the icon of the menu that toggles the visibility of grid
* columns.
*
* @param grid the grid to be configured
* @param label the text to show before the icon, or {@code null} to show the icon alone
*/
public static void setColumnToggleLabel(Grid<?> grid, String label) {
getHelper(grid).columnToggleHelper.setColumnToggleLabel(label);
}

/**
* Sets the vertical alignment of the menu that toggles the visibility of grid columns, relative to
* the first header row.
*
* @param grid the grid to be configured
* @param alignment the alignment of the column toggle, or {@code null} to restore the default
*/
public static void setColumnToggleAlignment(Grid<?> grid, Style.AlignItems alignment) {
getHelper(grid).columnToggleHelper.setColumnToggleAlignment(alignment);
}

/**
* Returns whether this column can be hidden by the user. Default is {@code false}.
*
Expand Down Expand Up @@ -362,8 +400,20 @@
return getHelper(column.getGrid()).columnToggleHelper.getHidingToggleCaption(column);
}

/**
* Returns whether the given column renders the column toggle.
*
* @param column the column to test, not {@code null}
* @return always {@code false}
* @throws NullPointerException if {@code column} is {@code null}
* @deprecated Since 2.2.0, the column toggle is rendered in the {@code fc-column-toggle} slot
* instead of in a dedicated column, so no column is a menu toggle column and this
* method always returns {@code false}.
*/
@Deprecated(forRemoval = true, since = "2.2.0")
Comment thread
paodb marked this conversation as resolved.
public static boolean isMenuToggleColumn(Column<?> column) {

Check warning on line 414 in src/main/java/com/flowingcode/vaadin/addons/gridhelpers/GridHelper.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Do not forget to remove this deprecated code someday.

See more on https://sonarcloud.io/project/issues?id=FlowingCode_GridHelpers&issues=AaAWT4dGC2CdRiH18wY6&open=AaAWT4dGC2CdRiH18wY6&pullRequest=180
return column == getHelper(column).columnToggleHelper.getMenuToggleColumn();
Objects.requireNonNull(column);
return false;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

// Empty Label
Expand Down
64 changes: 62 additions & 2 deletions src/main/resources/META-INF/frontend/fcGridHelper/connector.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,19 @@ import { Grid } from '@vaadin/grid/src/vaadin-grid.js';
(function () {
window.Vaadin.Flow.fcGridHelperConnector = {
initLazy: grid => {

// initLazy runs on every attach, and grid.fcGridHelper is replaced below,
// so the observers of the previous initialization have to be released here
if (grid.fcGridHelper) {
grid.fcGridHelper._toggleHeightResizeObserver.disconnect();
grid.fcGridHelper._toggleHeightMutationObserver?.disconnect();
}

if (!grid.shadowRoot.querySelector('slot[name="fc-column-toggle"]')) {
const slot = document.createElement('slot');
slot.setAttribute('name','fc-column-toggle');
grid.shadowRoot.appendChild(slot);
}

//https://cookbook.vaadin.com/grid-arrow-selection
grid.addEventListener('keyup', function(e) {
if (e.keyCode == 32) return;
Expand Down Expand Up @@ -138,9 +150,57 @@ import { Grid } from '@vaadin/grid/src/vaadin-grid.js';
observer.width=undefined;
grid.dispatchEvent(new CustomEvent("fcgh-responsive-step", { detail: {step: -1} }));
}
},

_toggleHeightResizeObserver : new ResizeObserver(() => {
grid.fcGridHelper._updateToggleHeight();
}),

// keep --_fc-grid-helper--header-row-height in sync with the first visible header row,
// so that the column toggle defaults to the height of that row
_observeToggleHeight : function() {
const thead = grid.shadowRoot.querySelector("thead#header");
if (!thead) return;

if (!grid.fcGridHelper._toggleHeightMutationObserver) {
grid.fcGridHelper._toggleHeightMutationObserver = new MutationObserver(() => {
grid.fcGridHelper._updateToggleHeight();
});
grid.fcGridHelper._toggleHeightMutationObserver.observe(thead,
{childList: true, subtree: true, attributes: true, attributeFilter: ['hidden']});
}

grid.fcGridHelper._updateToggleHeight();
},

_updateToggleHeight : function() {
const row = grid.shadowRoot.querySelector("thead#header tr:not([hidden])");
const observer = grid.fcGridHelper._toggleHeightResizeObserver;

if (row !== grid.fcGridHelper._toggleHeightRow) {
if (grid.fcGridHelper._toggleHeightRow) {
observer.unobserve(grid.fcGridHelper._toggleHeightRow);
}
grid.fcGridHelper._toggleHeightRow = row;
if (row) {
observer.observe(row);
}
}

const height = row ? row.getBoundingClientRect().height : 0;
if (height !== grid.fcGridHelper._toggleHeight) {
grid.fcGridHelper._toggleHeight = height;
if (height > 0) {
grid.style.setProperty('--_fc-grid-helper--header-row-height', height+'px');
} else {
grid.style.removeProperty('--_fc-grid-helper--header-row-height');
}
}
}

};

grid.fcGridHelper._observeToggleHeight();
}

}
Expand Down
Loading
Loading