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
4 changes: 4 additions & 0 deletions packages/modules/data-widgets/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased]

### Changed

- We enhanced datagrid selection UI with responsive container queries and improved layout styling for header and footer components.

## [3.5.0] DataWidgets - 2025-09-16

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ $root: ".widget-datagrid";
justify-content: flex-end;
white-space: nowrap;
align-items: baseline;
margin: 16px;
margin: 0 16px;
color: $pagination-caption-color;

.paging-status {
Expand Down Expand Up @@ -397,6 +397,10 @@ $root: ".widget-datagrid";
}
}

&-top-bar {
container: widget-datagrid-header / inline-size;
}

&-content {
overflow-x: auto;
}
Expand All @@ -409,6 +413,10 @@ $root: ".widget-datagrid";
display: contents;
}

&-footer {
container: widget-datagrid-footer / inline-size;
}

&.widget-datagrid-selection-method-click {
.tr.tr-selected .td {
background-color: $grid-selected-row-background;
Expand Down Expand Up @@ -517,7 +525,7 @@ $root: ".widget-datagrid";

.widget-datagrid .widget-datagrid-load-more {
display: block !important;
margin: 0 auto;
margin: 0;
}

:where(.widget-datagrid-grid.infinite-loading) {
Expand All @@ -529,21 +537,30 @@ $root: ".widget-datagrid";
z-index: 1;
}

:where(#{$root}-paging-bottom) {
:where(#{$root}-paging-bottom, #{$root}-padding-top) {
display: flex;
flex-flow: row nowrap;
align-items: center;
}

:where(#{$root}-pb-start, #{$root}-pb-end, #{$root}-pb-middle) {
:where(#{$root}-pb-end, #{$root}-tb-end) {
display: flex;
justify-content: flex-end;
align-items: center;
}

:where(#{$root}-pb-start, #{$root}-tb-start, #{$root}-pb-end, #{$root}-tb-end, #{$root}-pb-middle) {
flex-grow: 1;
flex-basis: 33.33%;
min-height: 20px;
height: 54px;
padding: var(--spacing-small) 0;
}

:where(#{$root}-pb-start) {
margin-block: var(--spacing-medium);
:where(#{$root}-pb-start, #{$root}-tb-start) {
padding-inline: var(--spacing-medium);
display: flex;
align-items: center;
}

#{$root}-clear-selection {
Expand All @@ -567,3 +584,23 @@ $root: ".widget-datagrid";
transform: rotate(1turn);
}
}

@container widget-datagrid-footer (width < 500px) {
#{$root}-paging-bottom {
flex-direction: column;
:where(#{$root}-pb-start, #{$root}-pb-end, #{$root}-pb-middle) {
width: 100%;
justify-content: center;
}
}
}

@container widget-datagrid-header (width < 500px) {
#{$root}-padding-top {
flex-direction: column-reverse;
:where(#{$root}-tb-start, #{$root}-tb-end) {
width: 100%;
justify-content: center;
}
}
}
4 changes: 4 additions & 0 deletions packages/pluggableWidgets/datagrid-web/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased]

### Added

- We added configurable selection count visibility and clear selection button label template for improved row selection management.

## [3.4.0] - 2025-09-12

### Fixed
Expand Down
1 change: 1 addition & 0 deletions packages/pluggableWidgets/datagrid-web/src/Datagrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ const Container = observer((props: Props): ReactElement => {
pageSize={props.pageSize}
paginationType={props.pagination}
loadMoreButtonCaption={props.loadMoreButtonCaption?.value}
selectionCountPosition={props.selectionCountPosition}
paging={paginationCtrl.showPagination}
pagingPosition={props.pagingPosition}
showPagingButtons={props.showPagingButtons}
Expand Down
16 changes: 16 additions & 0 deletions packages/pluggableWidgets/datagrid-web/src/Datagrid.xml
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,22 @@
<enumerationValue key="both">Both</enumerationValue>
</enumerationValues>
</property>
<property key="selectionCountPosition" type="enumeration" defaultValue="bottom" required="true">
<caption>Show selection count</caption>
<description />
<enumerationValues>
<enumerationValue key="top">Top</enumerationValue>
<enumerationValue key="bottom">Bottom</enumerationValue>
<enumerationValue key="off">Off</enumerationValue>
</enumerationValues>
</property>
<property key="clearSelectionButtonLabel" type="textTemplate" required="false">
<caption>Clear selection label</caption>
<description>Customize the label of the 'Clear section' button</description>
<translations>
<translation lang="en_US">Clear selection</translation>
</translations>
</property>
<property key="loadMoreButtonCaption" type="textTemplate" required="false">
<caption>Load more caption</caption>
<description />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { If } from "@mendix/widget-plugin-component-kit/If";
import { observer } from "mobx-react-lite";
import { createElement } from "react";
import { useDatagridRootScope } from "../helpers/root-context";

type SelectionCounterLocation = "top" | "bottom" | undefined;

export const SelectionCounter = observer(function SelectionCounter({
location
}: {
location?: SelectionCounterLocation;
}) {
const { selectionCountStore, selectActionHelper } = useDatagridRootScope();

const containerClass = location === "top" ? "widget-datagrid-tb-start" : "widget-datagrid-pb-start";

return (
<If condition={selectionCountStore.displayCount !== ""}>
<div className={containerClass}>
<span className="widget-datagrid-selection-count">{selectionCountStore.displayCount}</span>&nbsp;|&nbsp;
<button className="widget-datagrid-clear-selection" onClick={selectActionHelper.onClearSelection}>
{selectionCountStore.clearButtonLabel}
</button>
</div>
</If>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
LoadingTypeEnum,
PaginationEnum,
PagingPositionEnum,
SelectionCountPositionEnum,
ShowPagingButtonsEnum
} from "../../typings/DatagridProps";
import { SelectActionHelper } from "../helpers/SelectActionHelper";
Expand All @@ -25,6 +26,7 @@ import { WidgetFooter } from "./WidgetFooter";
import { WidgetHeader } from "./WidgetHeader";
import { WidgetRoot } from "./WidgetRoot";
import { WidgetTopBar } from "./WidgetTopBar";
import { SelectionCounter } from "./SelectionCounter";

export interface WidgetProps<C extends GridColumn, T extends ObjectItem = ObjectItem> {
CellComponent: CellComponent<C>;
Expand All @@ -48,6 +50,7 @@ export interface WidgetProps<C extends GridColumn, T extends ObjectItem = Object
page: number;
paginationType: PaginationEnum;
loadMoreButtonCaption?: string;
selectionCountPosition?: SelectionCountPositionEnum;
pageSize: number;
paging: boolean;
pagingPosition: PagingPositionEnum;
Expand Down Expand Up @@ -118,6 +121,7 @@ const Main = observer(<C extends GridColumn>(props: WidgetProps<C>): ReactElemen
headerContent,
headerTitle,
loadMoreButtonCaption,
selectionCountPosition,
numberOfItems,
page,
pageSize,
Expand All @@ -131,10 +135,11 @@ const Main = observer(<C extends GridColumn>(props: WidgetProps<C>): ReactElemen
visibleColumns
} = props;

const { basicData } = useDatagridRootScope();
const { basicData, selectionCountStore } = useDatagridRootScope();

const showHeader = !!headerContent;
const showTopBar = paging && (pagingPosition === "top" || pagingPosition === "both");
const showTopBarPagination = paging && (pagingPosition === "top" || pagingPosition === "both");
const showFooterPagination = paging && (pagingPosition === "bottom" || pagingPosition === "both");

const pagination = paging ? (
<Pagination
Expand All @@ -151,6 +156,14 @@ const Main = observer(<C extends GridColumn>(props: WidgetProps<C>): ReactElemen
/>
) : null;

const selectionCount =
selectionCountStore.selectedCount > 0 && selectionCountPosition !== "off" && selectionCountPosition ? (
<SelectionCounter location={selectionCountPosition} />
) : null;

const showTopbarSelectionCount = selectionCount && selectionCountPosition === "top";
const showFooterSelectionCount = selectionCount && selectionCountPosition === "bottom";

const cssGridStyles = gridStyle(visibleColumns, {
selectItemColumn: selectActionHelper.showCheckboxColumn,
visibilitySelectorColumn: columnsHidable
Expand All @@ -160,7 +173,10 @@ const Main = observer(<C extends GridColumn>(props: WidgetProps<C>): ReactElemen

return (
<Fragment>
{showTopBar && <WidgetTopBar>{pagination}</WidgetTopBar>}
<WidgetTopBar
pagination={showTopBarPagination ? pagination : undefined}
selectionCount={showTopbarSelectionCount ? selectionCount : undefined}
></WidgetTopBar>
{showHeader && <WidgetHeader headerTitle={headerTitle}>{headerContent}</WidgetHeader>}
<WidgetContent>
<Grid
Expand Down Expand Up @@ -231,8 +247,8 @@ const Main = observer(<C extends GridColumn>(props: WidgetProps<C>): ReactElemen
</Grid>
</WidgetContent>
<WidgetFooter
pagination={pagination}
pagingPosition={pagingPosition}
pagination={showFooterPagination ? pagination : undefined}
selectionCount={showFooterSelectionCount ? selectionCount : undefined}
paginationType={paginationType}
loadMoreButtonCaption={loadMoreButtonCaption}
hasMoreItems={hasMoreItems}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,54 +1,35 @@
import { If } from "@mendix/widget-plugin-component-kit/If";
import { observer } from "mobx-react-lite";
import { createElement, ReactElement, ReactNode } from "react";
import { PaginationEnum, PagingPositionEnum } from "../../typings/DatagridProps";
import { useDatagridRootScope } from "../helpers/root-context";
import { PaginationEnum } from "../../typings/DatagridProps";

type WidgetFooterProps = {
pagingPosition: PagingPositionEnum;
pagination: ReactNode;
selectionCount: ReactNode;
paginationType: PaginationEnum;
loadMoreButtonCaption?: string;
hasMoreItems: boolean;
setPage?: (computePage: (prevPage: number) => number) => void;
} & JSX.IntrinsicElements["div"];

export function WidgetFooter(props: WidgetFooterProps): ReactElement | null {
const { pagingPosition, pagination, paginationType, loadMoreButtonCaption, hasMoreItems, setPage, ...rest } = props;
const { pagination, selectionCount, paginationType, loadMoreButtonCaption, hasMoreItems, setPage, ...rest } = props;

return (
<div {...rest} className="widget-datagrid-footer table-footer">
<div className="widget-datagrid-paging-bottom">
<div className="widget-datagrid-pb-start">
<SelectionCounter />
</div>
{hasMoreItems && paginationType === "loadMore" && (
<div className="widget-datagrid-pb-middle">
{selectionCount}
<div className="widget-datagrid-pb-end">
{pagination}
{hasMoreItems && paginationType === "loadMore" && (
<button
className="btn btn-primary widget-datagrid-load-more"
onClick={() => setPage && setPage(prev => prev + 1)}
tabIndex={0}
>
{loadMoreButtonCaption}
</button>
</div>
)}
<div className="widget-datagrid-pb-end">
{(pagingPosition === "bottom" || pagingPosition === "both") && pagination}
)}
</div>
</div>
</div>
);
}

const SelectionCounter = observer(function SelectionCounter() {
const { selectionCountStore, selectActionHelper } = useDatagridRootScope();

return (
<If condition={selectionCountStore.displayCount !== ""}>
<span className="widget-datagrid-selection-count">{selectionCountStore.displayCount}</span>&nbsp;|&nbsp;
<button className="widget-datagrid-clear-selection" onClick={selectActionHelper.onClearSelection}>
Clear selection
</button>
</If>
);
});
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
import { createElement, ReactElement } from "react";
import { createElement, ReactElement, ReactNode } from "react";

type WidgetTopBarProps = {
pagination: ReactNode;
selectionCount: ReactNode;
} & JSX.IntrinsicElements["div"];

export function WidgetTopBar(props: WidgetTopBarProps): ReactElement {
const { pagination, selectionCount, ...rest } = props;

export function WidgetTopBar(props: JSX.IntrinsicElements["div"]): ReactElement {
return (
<div {...props} className="widget-datagrid-top-bar table-header">
{props.children}
<div {...rest} className="widget-datagrid-top-bar table-header">
<div className="widget-datagrid-padding-top">
{selectionCount}
{pagination && <div className="widget-datagrid-tb-end">{pagination}</div>}
</div>
</div>
);
}
Loading
Loading