From adcf567dd2745dd7f9a5e87b3c46c4a436b76724 Mon Sep 17 00:00:00 2001 From: Yordan Date: Mon, 15 Sep 2025 15:24:15 +0200 Subject: [PATCH 1/9] feat: add clear selection button label config --- .../datagrid-web/src/Datagrid.tsx | 1 + .../datagrid-web/src/Datagrid.xml | 7 ++++++ .../datagrid-web/src/components/Widget.tsx | 3 +++ .../src/components/WidgetFooter.tsx | 23 +++++++++++++++---- .../datagrid-web/typings/DatagridProps.d.ts | 2 ++ 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/packages/pluggableWidgets/datagrid-web/src/Datagrid.tsx b/packages/pluggableWidgets/datagrid-web/src/Datagrid.tsx index b1171e778d..f02c33324c 100644 --- a/packages/pluggableWidgets/datagrid-web/src/Datagrid.tsx +++ b/packages/pluggableWidgets/datagrid-web/src/Datagrid.tsx @@ -117,6 +117,7 @@ const Container = observer((props: Props): ReactElement => { pageSize={props.pageSize} paginationType={props.pagination} loadMoreButtonCaption={props.loadMoreButtonCaption?.value} + clearSelectionButtonLabel={props.clearSelectionButtonLabel?.value} paging={paginationCtrl.showPagination} pagingPosition={props.pagingPosition} showPagingButtons={props.showPagingButtons} diff --git a/packages/pluggableWidgets/datagrid-web/src/Datagrid.xml b/packages/pluggableWidgets/datagrid-web/src/Datagrid.xml index c19285b1cd..b5c2c08ef3 100644 --- a/packages/pluggableWidgets/datagrid-web/src/Datagrid.xml +++ b/packages/pluggableWidgets/datagrid-web/src/Datagrid.xml @@ -65,6 +65,13 @@ Show refresh indicator Show a refresh indicator when the data is being loaded. + + Clear selection + Customize the label of the 'Clear section' button + + Clear selection + + diff --git a/packages/pluggableWidgets/datagrid-web/src/components/Widget.tsx b/packages/pluggableWidgets/datagrid-web/src/components/Widget.tsx index 70b7ae1aed..7c5790efe2 100644 --- a/packages/pluggableWidgets/datagrid-web/src/components/Widget.tsx +++ b/packages/pluggableWidgets/datagrid-web/src/components/Widget.tsx @@ -48,6 +48,7 @@ export interface WidgetProps(props: WidgetProps): ReactElemen headerContent, headerTitle, loadMoreButtonCaption, + clearSelectionButtonLabel, numberOfItems, page, pageSize, @@ -235,6 +237,7 @@ const Main = observer((props: WidgetProps): ReactElemen pagingPosition={pagingPosition} paginationType={paginationType} loadMoreButtonCaption={loadMoreButtonCaption} + clearSelectionButtonLabel={clearSelectionButtonLabel} hasMoreItems={hasMoreItems} setPage={setPage} /> diff --git a/packages/pluggableWidgets/datagrid-web/src/components/WidgetFooter.tsx b/packages/pluggableWidgets/datagrid-web/src/components/WidgetFooter.tsx index 99b725d691..2c78ee77b9 100644 --- a/packages/pluggableWidgets/datagrid-web/src/components/WidgetFooter.tsx +++ b/packages/pluggableWidgets/datagrid-web/src/components/WidgetFooter.tsx @@ -9,17 +9,28 @@ type WidgetFooterProps = { pagination: ReactNode; paginationType: PaginationEnum; loadMoreButtonCaption?: string; + clearSelectionButtonLabel?: 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 { + pagingPosition, + pagination, + paginationType, + loadMoreButtonCaption, + clearSelectionButtonLabel, + hasMoreItems, + setPage, + ...rest + } = props; + return (
- +
{hasMoreItems && paginationType === "loadMore" && (
@@ -40,14 +51,18 @@ export function WidgetFooter(props: WidgetFooterProps): ReactElement | null { ); } -const SelectionCounter = observer(function SelectionCounter() { +const SelectionCounter = observer(function SelectionCounter({ + clearSelectionButtonLabel +}: { + clearSelectionButtonLabel?: string; +}) { const { selectionCountStore, selectActionHelper } = useDatagridRootScope(); return ( {selectionCountStore.displayCount} |  ); diff --git a/packages/pluggableWidgets/datagrid-web/typings/DatagridProps.d.ts b/packages/pluggableWidgets/datagrid-web/typings/DatagridProps.d.ts index a3e01d2e2d..a4c7983372 100644 --- a/packages/pluggableWidgets/datagrid-web/typings/DatagridProps.d.ts +++ b/packages/pluggableWidgets/datagrid-web/typings/DatagridProps.d.ts @@ -98,6 +98,7 @@ export interface DatagridContainerProps { keepSelection: boolean; loadingType: LoadingTypeEnum; refreshIndicator: boolean; + clearSelectionButtonLabel?: DynamicValue; columns: ColumnsType[]; columnsFilterable: boolean; pageSize: number; @@ -150,6 +151,7 @@ export interface DatagridPreviewProps { keepSelection: boolean; loadingType: LoadingTypeEnum; refreshIndicator: boolean; + clearSelectionButtonLabel: string; columns: ColumnsPreviewType[]; columnsFilterable: boolean; pageSize: number | null; From 3d86fa8c9e666c5bcce98128b81433b5899fb28a Mon Sep 17 00:00:00 2001 From: Yordan Date: Mon, 15 Sep 2025 17:06:25 +0200 Subject: [PATCH 2/9] feat: add selection count visibility to config --- .../datagrid-web/src/Datagrid.tsx | 1 + .../datagrid-web/src/Datagrid.xml | 23 +++++--- .../src/components/SelectionCounter.tsx | 21 ++++++++ .../datagrid-web/src/components/Widget.tsx | 15 +++++- .../src/components/WidgetFooter.tsx | 52 ++++--------------- .../src/components/WidgetTopBar.tsx | 18 +++++-- .../datagrid-web/typings/DatagridProps.d.ts | 8 ++- 7 files changed, 80 insertions(+), 58 deletions(-) create mode 100644 packages/pluggableWidgets/datagrid-web/src/components/SelectionCounter.tsx diff --git a/packages/pluggableWidgets/datagrid-web/src/Datagrid.tsx b/packages/pluggableWidgets/datagrid-web/src/Datagrid.tsx index f02c33324c..96f483dcf1 100644 --- a/packages/pluggableWidgets/datagrid-web/src/Datagrid.tsx +++ b/packages/pluggableWidgets/datagrid-web/src/Datagrid.tsx @@ -118,6 +118,7 @@ const Container = observer((props: Props): ReactElement => { paginationType={props.pagination} loadMoreButtonCaption={props.loadMoreButtonCaption?.value} clearSelectionButtonLabel={props.clearSelectionButtonLabel?.value} + selectionCountVisibility={props.selectionCountVisibility} paging={paginationCtrl.showPagination} pagingPosition={props.pagingPosition} showPagingButtons={props.showPagingButtons} diff --git a/packages/pluggableWidgets/datagrid-web/src/Datagrid.xml b/packages/pluggableWidgets/datagrid-web/src/Datagrid.xml index b5c2c08ef3..e5df826c81 100644 --- a/packages/pluggableWidgets/datagrid-web/src/Datagrid.xml +++ b/packages/pluggableWidgets/datagrid-web/src/Datagrid.xml @@ -65,13 +65,6 @@ Show refresh indicator Show a refresh indicator when the data is being loaded. - - Clear selection - Customize the label of the 'Clear section' button - - Clear selection - - @@ -251,6 +244,22 @@ Both + + Show selection count + + + Top + Bottom + Off + + + + Clear selection label + Customize the label of the 'Clear section' button + + Clear selection + + Load more caption diff --git a/packages/pluggableWidgets/datagrid-web/src/components/SelectionCounter.tsx b/packages/pluggableWidgets/datagrid-web/src/components/SelectionCounter.tsx new file mode 100644 index 0000000000..1c884a172f --- /dev/null +++ b/packages/pluggableWidgets/datagrid-web/src/components/SelectionCounter.tsx @@ -0,0 +1,21 @@ +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"; + +export const SelectionCounter = observer(function SelectionCounter({ + clearSelectionButtonLabel +}: { + clearSelectionButtonLabel?: string; +}) { + const { selectionCountStore, selectActionHelper } = useDatagridRootScope(); + + return ( + + {selectionCountStore.displayCount} |  + + + ); +}); diff --git a/packages/pluggableWidgets/datagrid-web/src/components/Widget.tsx b/packages/pluggableWidgets/datagrid-web/src/components/Widget.tsx index 7c5790efe2..957c60d0dd 100644 --- a/packages/pluggableWidgets/datagrid-web/src/components/Widget.tsx +++ b/packages/pluggableWidgets/datagrid-web/src/components/Widget.tsx @@ -9,7 +9,8 @@ import { LoadingTypeEnum, PaginationEnum, PagingPositionEnum, - ShowPagingButtonsEnum + ShowPagingButtonsEnum, + SelectionCountVisibilityEnum } from "../../typings/DatagridProps"; import { SelectActionHelper } from "../helpers/SelectActionHelper"; import { useDatagridRootScope } from "../helpers/root-context"; @@ -49,6 +50,7 @@ export interface WidgetProps(props: WidgetProps): ReactElemen headerTitle, loadMoreButtonCaption, clearSelectionButtonLabel, + selectionCountVisibility, numberOfItems, page, pageSize, @@ -162,7 +165,14 @@ const Main = observer((props: WidgetProps): ReactElemen return ( - {showTopBar && {pagination}} + {showTopBar && ( + + {pagination} + + )} {showHeader && {headerContent}} (props: WidgetProps): ReactElemen paginationType={paginationType} loadMoreButtonCaption={loadMoreButtonCaption} clearSelectionButtonLabel={clearSelectionButtonLabel} + selectionCountVisibility={selectionCountVisibility} hasMoreItems={hasMoreItems} setPage={setPage} /> diff --git a/packages/pluggableWidgets/datagrid-web/src/components/WidgetFooter.tsx b/packages/pluggableWidgets/datagrid-web/src/components/WidgetFooter.tsx index 2c78ee77b9..563cf379e7 100644 --- a/packages/pluggableWidgets/datagrid-web/src/components/WidgetFooter.tsx +++ b/packages/pluggableWidgets/datagrid-web/src/components/WidgetFooter.tsx @@ -1,39 +1,25 @@ -import { If } from "@mendix/widget-plugin-component-kit/If"; -import { observer } from "mobx-react-lite"; -import { JSX, ReactElement, ReactNode } from "react"; -import { PaginationEnum, PagingPositionEnum } from "../../typings/DatagridProps"; -import { useDatagridRootScope } from "../helpers/root-context"; +import { ReactElement, ReactNode } from "react"; +import { PaginationEnum } from "../../typings/DatagridProps"; type WidgetFooterProps = { - pagingPosition: PagingPositionEnum; pagination: ReactNode; + selectionCount: ReactNode; paginationType: PaginationEnum; loadMoreButtonCaption?: string; - clearSelectionButtonLabel?: string; hasMoreItems: boolean; setPage?: (computePage: (prevPage: number) => number) => void; } & JSX.IntrinsicElements["div"]; export function WidgetFooter(props: WidgetFooterProps): ReactElement | null { - const { - pagingPosition, - pagination, - paginationType, - loadMoreButtonCaption, - clearSelectionButtonLabel, - hasMoreItems, - setPage, - ...rest - } = props; + const { pagination, selectionCount, paginationType, loadMoreButtonCaption, hasMoreItems, setPage, ...rest } = props; return (
-
- -
- {hasMoreItems && paginationType === "loadMore" && ( -
+ {selectionCount} +
+ {pagination} + {hasMoreItems && paginationType === "loadMore" && ( -
- )} -
- {(pagingPosition === "bottom" || pagingPosition === "both") && pagination} + )}
); } - -const SelectionCounter = observer(function SelectionCounter({ - clearSelectionButtonLabel -}: { - clearSelectionButtonLabel?: string; -}) { - const { selectionCountStore, selectActionHelper } = useDatagridRootScope(); - - return ( - - {selectionCountStore.displayCount} |  - - - ); -}); diff --git a/packages/pluggableWidgets/datagrid-web/src/components/WidgetTopBar.tsx b/packages/pluggableWidgets/datagrid-web/src/components/WidgetTopBar.tsx index 284e5fd6a3..1a539fc090 100644 --- a/packages/pluggableWidgets/datagrid-web/src/components/WidgetTopBar.tsx +++ b/packages/pluggableWidgets/datagrid-web/src/components/WidgetTopBar.tsx @@ -1,9 +1,19 @@ -import { JSX, ReactElement } from "react"; +import { 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 ( -
- {props.children} +
+
+ {selectionCount} + {pagination &&
{pagination}
} +
); } diff --git a/packages/pluggableWidgets/datagrid-web/typings/DatagridProps.d.ts b/packages/pluggableWidgets/datagrid-web/typings/DatagridProps.d.ts index a4c7983372..d61b596773 100644 --- a/packages/pluggableWidgets/datagrid-web/typings/DatagridProps.d.ts +++ b/packages/pluggableWidgets/datagrid-web/typings/DatagridProps.d.ts @@ -53,6 +53,8 @@ export type ShowPagingButtonsEnum = "always" | "auto"; export type PagingPositionEnum = "bottom" | "top" | "both"; +export type SelectionCountVisibilityEnum = "top" | "bottom" | "off"; + export type ShowEmptyPlaceholderEnum = "none" | "custom"; export type OnClickTriggerEnum = "single" | "double"; @@ -98,7 +100,6 @@ export interface DatagridContainerProps { keepSelection: boolean; loadingType: LoadingTypeEnum; refreshIndicator: boolean; - clearSelectionButtonLabel?: DynamicValue; columns: ColumnsType[]; columnsFilterable: boolean; pageSize: number; @@ -106,6 +107,8 @@ export interface DatagridContainerProps { showPagingButtons: ShowPagingButtonsEnum; showNumberOfRows: boolean; pagingPosition: PagingPositionEnum; + selectionCountVisibility: SelectionCountVisibilityEnum; + clearSelectionButtonLabel?: DynamicValue; loadMoreButtonCaption?: DynamicValue; showEmptyPlaceholder: ShowEmptyPlaceholderEnum; emptyPlaceholder?: ReactNode; @@ -151,7 +154,6 @@ export interface DatagridPreviewProps { keepSelection: boolean; loadingType: LoadingTypeEnum; refreshIndicator: boolean; - clearSelectionButtonLabel: string; columns: ColumnsPreviewType[]; columnsFilterable: boolean; pageSize: number | null; @@ -159,6 +161,8 @@ export interface DatagridPreviewProps { showPagingButtons: ShowPagingButtonsEnum; showNumberOfRows: boolean; pagingPosition: PagingPositionEnum; + selectionCountVisibility: SelectionCountVisibilityEnum; + clearSelectionButtonLabel: string; loadMoreButtonCaption: string; showEmptyPlaceholder: ShowEmptyPlaceholderEnum; emptyPlaceholder: { widgetCount: number; renderer: ComponentType<{ children: ReactNode; caption?: string }> }; From ca95c0ae134350459770f02a8867dbe16369858b Mon Sep 17 00:00:00 2001 From: Yordan Date: Fri, 19 Sep 2025 15:53:13 +0200 Subject: [PATCH 3/9] fix: reference to updated scss variable --- packages/modules/data-widgets/CHANGELOG.md | 4 + .../datawidgets/web/_datagrid.scss | 49 +++++- .../datagrid-web/CHANGELOG.md | 4 + .../datagrid-web/src/components/Widget.tsx | 26 +-- .../__snapshots__/Table.spec.tsx.snap | 160 ++++++++++++------ 5 files changed, 177 insertions(+), 66 deletions(-) diff --git a/packages/modules/data-widgets/CHANGELOG.md b/packages/modules/data-widgets/CHANGELOG.md index 49f6017a3c..cbe8b68f9c 100644 --- a/packages/modules/data-widgets/CHANGELOG.md +++ b/packages/modules/data-widgets/CHANGELOG.md @@ -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.6.1] DataWidgets - 2025-10-14 ### [3.6.1] Datagrid diff --git a/packages/modules/data-widgets/src/themesource/datawidgets/web/_datagrid.scss b/packages/modules/data-widgets/src/themesource/datawidgets/web/_datagrid.scss index e6ecaea017..84673f7b95 100644 --- a/packages/modules/data-widgets/src/themesource/datawidgets/web/_datagrid.scss +++ b/packages/modules/data-widgets/src/themesource/datawidgets/web/_datagrid.scss @@ -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 { @@ -397,6 +397,10 @@ $root: ".widget-datagrid"; } } + &-top-bar { + container: widget-datagrid-header / inline-size; + } + &-content { overflow-x: auto; } @@ -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; @@ -517,7 +525,7 @@ $root: ".widget-datagrid"; .widget-datagrid .widget-datagrid-load-more { display: block !important; - margin: 0 auto; + margin: 0; } .infinite-loading.widget-datagrid-grid-body { @@ -540,21 +548,30 @@ $root: ".widget-datagrid"; grid-column: 1 / -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 { @@ -578,3 +595,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; + } + } +} diff --git a/packages/pluggableWidgets/datagrid-web/CHANGELOG.md b/packages/pluggableWidgets/datagrid-web/CHANGELOG.md index a859f8820c..9eb1114fff 100644 --- a/packages/pluggableWidgets/datagrid-web/CHANGELOG.md +++ b/packages/pluggableWidgets/datagrid-web/CHANGELOG.md @@ -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.6.1] - 2025-10-14 ### Fixed diff --git a/packages/pluggableWidgets/datagrid-web/src/components/Widget.tsx b/packages/pluggableWidgets/datagrid-web/src/components/Widget.tsx index 957c60d0dd..f3fe616f32 100644 --- a/packages/pluggableWidgets/datagrid-web/src/components/Widget.tsx +++ b/packages/pluggableWidgets/datagrid-web/src/components/Widget.tsx @@ -9,8 +9,8 @@ import { LoadingTypeEnum, PaginationEnum, PagingPositionEnum, - ShowPagingButtonsEnum, - SelectionCountVisibilityEnum + SelectionCountVisibilityEnum, + ShowPagingButtonsEnum } from "../../typings/DatagridProps"; import { SelectActionHelper } from "../helpers/SelectActionHelper"; import { useDatagridRootScope } from "../helpers/root-context"; @@ -136,10 +136,11 @@ const Main = observer((props: WidgetProps): ReactElemen visibleColumns } = props; - const { basicData } = useDatagridRootScope(); + const { basicData, selectionCountStore } = useDatagridRootScope(); const showHeader = !!headerContent; const showTopBar = paging && (pagingPosition === "top" || pagingPosition === "both"); + const showFooter = paging && (pagingPosition === "bottom" || pagingPosition === "both"); const pagination = paging ? ( (props: WidgetProps): ReactElemen return ( - {showTopBar && ( - - {pagination} - - )} + + {pagination} + {showHeader && {headerContent}} (props: WidgetProps): ReactElemen +
+
+
@@ -74,9 +81,6 @@ exports[`Table renders the structure correctly 1`] = `
-
@@ -91,6 +95,13 @@ exports[`Table renders the structure correctly for preview when no header is pro
+
+
+
@@ -160,9 +171,6 @@ exports[`Table renders the structure correctly for preview when no header is pro
-
@@ -177,6 +185,13 @@ exports[`Table renders the structure correctly with column alignments 1`] = `
+
+
+
@@ -279,9 +294,6 @@ exports[`Table renders the structure correctly with column alignments 1`] = `
-
@@ -296,6 +308,13 @@ exports[`Table renders the structure correctly with custom filtering 1`] = `
+
+
+
@@ -369,9 +388,6 @@ exports[`Table renders the structure correctly with custom filtering 1`] = `
-
@@ -386,6 +402,13 @@ exports[`Table renders the structure correctly with dragging 1`] = `
+
+
+
@@ -455,9 +478,6 @@ exports[`Table renders the structure correctly with dragging 1`] = `
-
@@ -472,6 +492,13 @@ exports[`Table renders the structure correctly with dynamic row class 1`] = `
+
+
+
@@ -541,9 +568,6 @@ exports[`Table renders the structure correctly with dynamic row class 1`] = `
-
@@ -558,6 +582,13 @@ exports[`Table renders the structure correctly with empty placeholder 1`] = `
+
+
+
@@ -627,9 +658,6 @@ exports[`Table renders the structure correctly with empty placeholder 1`] = `
-
@@ -644,6 +672,13 @@ exports[`Table renders the structure correctly with filtering 1`] = `
+
+
+
@@ -717,9 +752,6 @@ exports[`Table renders the structure correctly with filtering 1`] = `
-
@@ -734,6 +766,13 @@ exports[`Table renders the structure correctly with header filters and a11y 1`]
+
+
+
-
@@ -830,6 +866,13 @@ exports[`Table renders the structure correctly with header wrapper 1`] = `
+
+
+
@@ -903,9 +946,6 @@ exports[`Table renders the structure correctly with header wrapper 1`] = `
-
@@ -920,6 +960,13 @@ exports[`Table renders the structure correctly with hiding 1`] = `
+
+
+
@@ -1030,9 +1077,6 @@ exports[`Table renders the structure correctly with hiding 1`] = `
-
@@ -1047,6 +1091,13 @@ exports[`Table renders the structure correctly with paging 1`] = `
+
+
+
@@ -1116,9 +1167,6 @@ exports[`Table renders the structure correctly with paging 1`] = `
-
@@ -1223,6 +1271,13 @@ exports[`Table renders the structure correctly with resizing 1`] = `
+
+
+
@@ -1292,9 +1347,6 @@ exports[`Table renders the structure correctly with resizing 1`] = `
-
@@ -1309,6 +1361,13 @@ exports[`Table renders the structure correctly with sorting 1`] = `
+
+
+
@@ -1378,9 +1437,6 @@ exports[`Table renders the structure correctly with sorting 1`] = `
-
@@ -1395,6 +1451,13 @@ exports[`Table with selection method checkbox render an extra column and add cla
+
+
+
@@ -1545,9 +1608,6 @@ exports[`Table with selection method checkbox render an extra column and add cla
-
@@ -1652,6 +1712,13 @@ exports[`Table with selection method rowClick add class to each selected cell 1`
+
+
+
@@ -1759,9 +1826,6 @@ exports[`Table with selection method rowClick add class to each selected cell 1`
-
From 91d902ef0b4b26521c3e82c726c6c009434775cc Mon Sep 17 00:00:00 2001 From: Yordan Date: Thu, 25 Sep 2025 16:20:25 +0200 Subject: [PATCH 4/9] refactor: improve naming, reduce prop drilling and unify component rendering --- .../datagrid-web/src/Datagrid.tsx | 3 +- .../datagrid-web/src/Datagrid.xml | 2 +- .../src/components/SelectionCounter.tsx | 18 ++++++--- .../datagrid-web/src/components/Widget.tsx | 38 +++++++++---------- .../src/helpers/state/RootGridStore.ts | 1 + .../datagrid-web/typings/DatagridProps.d.ts | 6 +-- .../selection/stores/SelectionCountStore.ts | 12 +++++- 7 files changed, 47 insertions(+), 33 deletions(-) diff --git a/packages/pluggableWidgets/datagrid-web/src/Datagrid.tsx b/packages/pluggableWidgets/datagrid-web/src/Datagrid.tsx index 96f483dcf1..82dcc6a041 100644 --- a/packages/pluggableWidgets/datagrid-web/src/Datagrid.tsx +++ b/packages/pluggableWidgets/datagrid-web/src/Datagrid.tsx @@ -117,8 +117,7 @@ const Container = observer((props: Props): ReactElement => { pageSize={props.pageSize} paginationType={props.pagination} loadMoreButtonCaption={props.loadMoreButtonCaption?.value} - clearSelectionButtonLabel={props.clearSelectionButtonLabel?.value} - selectionCountVisibility={props.selectionCountVisibility} + selectionCountPosition={props.selectionCountPosition} paging={paginationCtrl.showPagination} pagingPosition={props.pagingPosition} showPagingButtons={props.showPagingButtons} diff --git a/packages/pluggableWidgets/datagrid-web/src/Datagrid.xml b/packages/pluggableWidgets/datagrid-web/src/Datagrid.xml index e5df826c81..a1edb73ec2 100644 --- a/packages/pluggableWidgets/datagrid-web/src/Datagrid.xml +++ b/packages/pluggableWidgets/datagrid-web/src/Datagrid.xml @@ -244,7 +244,7 @@ Both - + Show selection count diff --git a/packages/pluggableWidgets/datagrid-web/src/components/SelectionCounter.tsx b/packages/pluggableWidgets/datagrid-web/src/components/SelectionCounter.tsx index 1c884a172f..8ba2c046e6 100644 --- a/packages/pluggableWidgets/datagrid-web/src/components/SelectionCounter.tsx +++ b/packages/pluggableWidgets/datagrid-web/src/components/SelectionCounter.tsx @@ -3,19 +3,25 @@ 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({ - clearSelectionButtonLabel + location }: { - clearSelectionButtonLabel?: string; + location?: SelectionCounterLocation; }) { const { selectionCountStore, selectActionHelper } = useDatagridRootScope(); + const containerClass = location === "top" ? "widget-datagrid-tb-start" : "widget-datagrid-pb-start"; + return ( - {selectionCountStore.displayCount} |  - +
+ {selectionCountStore.displayCount} |  + +
); }); diff --git a/packages/pluggableWidgets/datagrid-web/src/components/Widget.tsx b/packages/pluggableWidgets/datagrid-web/src/components/Widget.tsx index f3fe616f32..5b7644a280 100644 --- a/packages/pluggableWidgets/datagrid-web/src/components/Widget.tsx +++ b/packages/pluggableWidgets/datagrid-web/src/components/Widget.tsx @@ -9,7 +9,7 @@ import { LoadingTypeEnum, PaginationEnum, PagingPositionEnum, - SelectionCountVisibilityEnum, + SelectionCountPositionEnum, ShowPagingButtonsEnum } from "../../typings/DatagridProps"; import { SelectActionHelper } from "../helpers/SelectActionHelper"; @@ -26,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 { CellComponent: CellComponent; @@ -49,8 +50,7 @@ export interface WidgetProps(props: WidgetProps): ReactElemen headerContent, headerTitle, loadMoreButtonCaption, - clearSelectionButtonLabel, - selectionCountVisibility, + selectionCountPosition, numberOfItems, page, pageSize, @@ -139,8 +138,8 @@ const Main = observer((props: WidgetProps): ReactElemen const { basicData, selectionCountStore } = useDatagridRootScope(); const showHeader = !!headerContent; - const showTopBar = paging && (pagingPosition === "top" || pagingPosition === "both"); - const showFooter = paging && (pagingPosition === "bottom" || pagingPosition === "both"); + const showTopBarPagination = paging && (pagingPosition === "top" || pagingPosition === "both"); + const showFooterPagination = paging && (pagingPosition === "bottom" || pagingPosition === "both"); const pagination = paging ? ( (props: WidgetProps): ReactElemen /> ) : null; + const selectionCount = + selectionCountStore.selectedCount > 0 && selectionCountPosition !== "off" && selectionCountPosition ? ( + + ) : null; + + const showTopbarSelectionCount = selectionCount && selectionCountPosition === "top"; + const showFooterSelectionCount = selectionCount && selectionCountPosition === "bottom"; + const cssGridStyles = gridStyle(visibleColumns, { selectItemColumn: selectActionHelper.showCheckboxColumn, visibilitySelectorColumn: columnsHidable @@ -167,13 +174,9 @@ const Main = observer((props: WidgetProps): ReactElemen return ( - {pagination} - + pagination={showTopBarPagination ? pagination : undefined} + selectionCount={showTopbarSelectionCount ? selectionCount : undefined} + > {showHeader && {headerContent}} (props: WidgetProps): ReactElemen diff --git a/packages/pluggableWidgets/datagrid-web/src/helpers/state/RootGridStore.ts b/packages/pluggableWidgets/datagrid-web/src/helpers/state/RootGridStore.ts index 7e64c08ec0..c1644d2ea0 100644 --- a/packages/pluggableWidgets/datagrid-web/src/helpers/state/RootGridStore.ts +++ b/packages/pluggableWidgets/datagrid-web/src/helpers/state/RootGridStore.ts @@ -34,6 +34,7 @@ type RequiredProps = Pick< | "pagination" | "showPagingButtons" | "showNumberOfRows" + | "clearSelectionButtonLabel" >; type Gate = DerivedPropsGate; diff --git a/packages/pluggableWidgets/datagrid-web/typings/DatagridProps.d.ts b/packages/pluggableWidgets/datagrid-web/typings/DatagridProps.d.ts index d61b596773..1b5baa1072 100644 --- a/packages/pluggableWidgets/datagrid-web/typings/DatagridProps.d.ts +++ b/packages/pluggableWidgets/datagrid-web/typings/DatagridProps.d.ts @@ -53,7 +53,7 @@ export type ShowPagingButtonsEnum = "always" | "auto"; export type PagingPositionEnum = "bottom" | "top" | "both"; -export type SelectionCountVisibilityEnum = "top" | "bottom" | "off"; +export type SelectionCountPositionEnum = "top" | "bottom" | "off"; export type ShowEmptyPlaceholderEnum = "none" | "custom"; @@ -107,7 +107,7 @@ export interface DatagridContainerProps { showPagingButtons: ShowPagingButtonsEnum; showNumberOfRows: boolean; pagingPosition: PagingPositionEnum; - selectionCountVisibility: SelectionCountVisibilityEnum; + selectionCountPosition: SelectionCountPositionEnum; clearSelectionButtonLabel?: DynamicValue; loadMoreButtonCaption?: DynamicValue; showEmptyPlaceholder: ShowEmptyPlaceholderEnum; @@ -161,7 +161,7 @@ export interface DatagridPreviewProps { showPagingButtons: ShowPagingButtonsEnum; showNumberOfRows: boolean; pagingPosition: PagingPositionEnum; - selectionCountVisibility: SelectionCountVisibilityEnum; + selectionCountPosition: SelectionCountPositionEnum; clearSelectionButtonLabel: string; loadMoreButtonCaption: string; showEmptyPlaceholder: ShowEmptyPlaceholderEnum; diff --git a/packages/shared/widget-plugin-grid/src/selection/stores/SelectionCountStore.ts b/packages/shared/widget-plugin-grid/src/selection/stores/SelectionCountStore.ts index 96227850a2..73b2a6a93a 100644 --- a/packages/shared/widget-plugin-grid/src/selection/stores/SelectionCountStore.ts +++ b/packages/shared/widget-plugin-grid/src/selection/stores/SelectionCountStore.ts @@ -6,26 +6,34 @@ type Gate = DerivedPropsGate<{ itemSelection?: SelectionSingleValue | SelectionMultiValue; selectedCountTemplateSingular?: DynamicValue; selectedCountTemplatePlural?: DynamicValue; + clearSelectionButtonLabel?: DynamicValue; }>; export class SelectionCountStore { private gate: Gate; private singular: string = "%d row selected"; private plural: string = "%d rows selected"; + private defaultClearLabel: string = "Clear selection"; - constructor(gate: Gate, spec: { singular?: string; plural?: string } = {}) { + constructor(gate: Gate, spec: { singular?: string; plural?: string; clearLabel?: string } = {}) { this.singular = spec.singular ?? this.singular; this.plural = spec.plural ?? this.plural; + this.defaultClearLabel = spec.clearLabel ?? this.defaultClearLabel; this.gate = gate; makeObservable(this, { displayCount: computed, selectedCount: computed, fmtSingular: computed, - fmtPlural: computed + fmtPlural: computed, + clearButtonLabel: computed }); } + get clearButtonLabel(): string { + return this.gate.props.clearSelectionButtonLabel?.value || this.defaultClearLabel; + } + get fmtSingular(): string { return this.gate.props.selectedCountTemplateSingular?.value || this.singular; } From f2b68cd74d2933a19641b6e30b87ef9de750adb3 Mon Sep 17 00:00:00 2001 From: Yordan Date: Tue, 14 Oct 2025 16:57:34 +0200 Subject: [PATCH 5/9] fix: change selection count position and visibility, enhance accessibility support --- .../datagrid-web/src/Datagrid.editorConfig.ts | 7 +++- .../datagrid-web/src/Datagrid.xml | 32 +++++++++---------- .../src/components/SelectionCounter.tsx | 13 ++++++-- .../datagrid-web/typings/DatagridProps.d.ts | 12 +++---- 4 files changed, 39 insertions(+), 25 deletions(-) diff --git a/packages/pluggableWidgets/datagrid-web/src/Datagrid.editorConfig.ts b/packages/pluggableWidgets/datagrid-web/src/Datagrid.editorConfig.ts index 2139f6870d..abd7f1cfb2 100644 --- a/packages/pluggableWidgets/datagrid-web/src/Datagrid.editorConfig.ts +++ b/packages/pluggableWidgets/datagrid-web/src/Datagrid.editorConfig.ts @@ -75,6 +75,7 @@ export function getProperties( ]); } }); + if (values.pagination === "buttons") { hidePropertyIn(defaultProperties, values, "showNumberOfRows"); } else { @@ -169,7 +170,11 @@ function hideSelectionProperties(defaultProperties: Properties, values: Datagrid } if (itemSelection !== "Multi") { - hidePropertyIn(defaultProperties, values, "keepSelection"); + hidePropertiesIn(defaultProperties, values, [ + "keepSelection", + "selectionCountPosition", + "clearSelectionButtonLabel" + ]); } } diff --git a/packages/pluggableWidgets/datagrid-web/src/Datagrid.xml b/packages/pluggableWidgets/datagrid-web/src/Datagrid.xml index a1edb73ec2..afb1d00ec4 100644 --- a/packages/pluggableWidgets/datagrid-web/src/Datagrid.xml +++ b/packages/pluggableWidgets/datagrid-web/src/Datagrid.xml @@ -53,6 +53,22 @@ Keep selection If enabled, selected items will stay selected unless cleared by the user or a Nanoflow.
+ + Show selection count + + + Top + Bottom + Off + + + + Clear selection label + Customize the label of the 'Clear section' button + + Clear selection + + Loading type @@ -244,22 +260,6 @@ Both - - Show selection count - - - Top - Bottom - Off - - - - Clear selection label - Customize the label of the 'Clear section' button - - Clear selection - - Load more caption diff --git a/packages/pluggableWidgets/datagrid-web/src/components/SelectionCounter.tsx b/packages/pluggableWidgets/datagrid-web/src/components/SelectionCounter.tsx index 8ba2c046e6..5e4d32ba16 100644 --- a/packages/pluggableWidgets/datagrid-web/src/components/SelectionCounter.tsx +++ b/packages/pluggableWidgets/datagrid-web/src/components/SelectionCounter.tsx @@ -14,11 +14,20 @@ export const SelectionCounter = observer(function SelectionCounter({ const containerClass = location === "top" ? "widget-datagrid-tb-start" : "widget-datagrid-pb-start"; + const clearButtonAriaLabel = `${selectionCountStore.clearButtonLabel} (${selectionCountStore.selectedCount} selected)`; + return (
- {selectionCountStore.displayCount} |  -
diff --git a/packages/pluggableWidgets/datagrid-web/typings/DatagridProps.d.ts b/packages/pluggableWidgets/datagrid-web/typings/DatagridProps.d.ts index 1b5baa1072..513d2d6282 100644 --- a/packages/pluggableWidgets/datagrid-web/typings/DatagridProps.d.ts +++ b/packages/pluggableWidgets/datagrid-web/typings/DatagridProps.d.ts @@ -11,6 +11,8 @@ export type ItemSelectionMethodEnum = "checkbox" | "rowClick"; export type ItemSelectionModeEnum = "toggle" | "clear"; +export type SelectionCountPositionEnum = "top" | "bottom" | "off"; + export type LoadingTypeEnum = "spinner" | "skeleton"; export type ShowContentAsEnum = "attribute" | "dynamicText" | "customContent"; @@ -53,8 +55,6 @@ export type ShowPagingButtonsEnum = "always" | "auto"; export type PagingPositionEnum = "bottom" | "top" | "both"; -export type SelectionCountPositionEnum = "top" | "bottom" | "off"; - export type ShowEmptyPlaceholderEnum = "none" | "custom"; export type OnClickTriggerEnum = "single" | "double"; @@ -98,6 +98,8 @@ export interface DatagridContainerProps { itemSelectionMode: ItemSelectionModeEnum; showSelectAllToggle: boolean; keepSelection: boolean; + selectionCountPosition: SelectionCountPositionEnum; + clearSelectionButtonLabel?: DynamicValue; loadingType: LoadingTypeEnum; refreshIndicator: boolean; columns: ColumnsType[]; @@ -107,8 +109,6 @@ export interface DatagridContainerProps { showPagingButtons: ShowPagingButtonsEnum; showNumberOfRows: boolean; pagingPosition: PagingPositionEnum; - selectionCountPosition: SelectionCountPositionEnum; - clearSelectionButtonLabel?: DynamicValue; loadMoreButtonCaption?: DynamicValue; showEmptyPlaceholder: ShowEmptyPlaceholderEnum; emptyPlaceholder?: ReactNode; @@ -152,6 +152,8 @@ export interface DatagridPreviewProps { itemSelectionMode: ItemSelectionModeEnum; showSelectAllToggle: boolean; keepSelection: boolean; + selectionCountPosition: SelectionCountPositionEnum; + clearSelectionButtonLabel: string; loadingType: LoadingTypeEnum; refreshIndicator: boolean; columns: ColumnsPreviewType[]; @@ -161,8 +163,6 @@ export interface DatagridPreviewProps { showPagingButtons: ShowPagingButtonsEnum; showNumberOfRows: boolean; pagingPosition: PagingPositionEnum; - selectionCountPosition: SelectionCountPositionEnum; - clearSelectionButtonLabel: string; loadMoreButtonCaption: string; showEmptyPlaceholder: ShowEmptyPlaceholderEnum; emptyPlaceholder: { widgetCount: number; renderer: ComponentType<{ children: ReactNode; caption?: string }> }; From a8bbfda15008be728ef2ce561456e7fe48beac14 Mon Sep 17 00:00:00 2001 From: Yordan Date: Tue, 14 Oct 2025 16:57:34 +0200 Subject: [PATCH 6/9] chore: enhance focus styles for accessibility in datagrid component --- .../src/themesource/datawidgets/web/_datagrid.scss | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/modules/data-widgets/src/themesource/datawidgets/web/_datagrid.scss b/packages/modules/data-widgets/src/themesource/datawidgets/web/_datagrid.scss index 84673f7b95..48aac22092 100644 --- a/packages/modules/data-widgets/src/themesource/datawidgets/web/_datagrid.scss +++ b/packages/modules/data-widgets/src/themesource/datawidgets/web/_datagrid.scss @@ -582,6 +582,15 @@ $root: ".widget-datagrid"; color: var(--link-color); padding: 0; display: inline-block; + + &:focus:not(:focus-visible) { + outline: none; + } + + &:focus-visible { + outline: 1px solid var(--brand-primary, $brand-primary); + outline-offset: 2px; + } } @keyframes skeleton-loading { From 448ecc60bad9600ea36a6cfa6ef5299d78dc9223 Mon Sep 17 00:00:00 2001 From: Yordan Date: Thu, 16 Oct 2025 10:23:22 +0200 Subject: [PATCH 7/9] fix: update focus-visible outline to use CSS variable for consistency --- .../src/themesource/datawidgets/web/_export-alert.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/modules/data-widgets/src/themesource/datawidgets/web/_export-alert.scss b/packages/modules/data-widgets/src/themesource/datawidgets/web/_export-alert.scss index b3e5460690..42883df20c 100644 --- a/packages/modules/data-widgets/src/themesource/datawidgets/web/_export-alert.scss +++ b/packages/modules/data-widgets/src/themesource/datawidgets/web/_export-alert.scss @@ -20,7 +20,7 @@ display: flex; padding: 4px; &:focus-visible { - outline: 1px solid $brand-primary; + outline: 1px solid var(--brand-primary, $brand-primary); } } } From 872ee760bd410ccb7e5aa7353dffec46d9e73a95 Mon Sep 17 00:00:00 2001 From: Yordan Date: Thu, 16 Oct 2025 14:47:53 +0200 Subject: [PATCH 8/9] fix: fix failing e2e --- packages/modules/data-widgets/CHANGELOG.md | 1 + .../themesource/datawidgets/web/_gallery.scss | 60 ++++- .../src/hocs/withParentProvidedEnumStore.tsx | 2 +- .../src/components/SelectionCounter.tsx | 1 - .../src/components/WidgetFooter.tsx | 2 +- .../pluggableWidgets/gallery-web/CHANGELOG.md | 4 + .../gallery-web/src/Gallery.editorConfig.ts | 6 +- .../gallery-web/src/Gallery.editorPreview.tsx | 2 +- .../gallery-web/src/Gallery.tsx | 1 + .../gallery-web/src/Gallery.xml | 16 ++ .../gallery-web/src/components/Gallery.tsx | 63 +++-- .../src/components/SelectionCounter.tsx | 29 +- .../__snapshots__/Gallery.spec.tsx.snap | 255 +++++++++--------- .../gallery-web/src/utils/test-utils.tsx | 3 +- .../gallery-web/typings/GalleryProps.d.ts | 6 + 15 files changed, 285 insertions(+), 166 deletions(-) diff --git a/packages/modules/data-widgets/CHANGELOG.md b/packages/modules/data-widgets/CHANGELOG.md index cbe8b68f9c..ed248754fe 100644 --- a/packages/modules/data-widgets/CHANGELOG.md +++ b/packages/modules/data-widgets/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Changed - We enhanced datagrid selection UI with responsive container queries and improved layout styling for header and footer components. +- We enhanced gallery selection UI with responsive container queries and improved layout styling for header and footer components to match datagrid implementation. ## [3.6.1] DataWidgets - 2025-10-14 diff --git a/packages/modules/data-widgets/src/themesource/datawidgets/web/_gallery.scss b/packages/modules/data-widgets/src/themesource/datawidgets/web/_gallery.scss index 1269d26e6a..e9a49a6fef 100644 --- a/packages/modules/data-widgets/src/themesource/datawidgets/web/_gallery.scss +++ b/packages/modules/data-widgets/src/themesource/datawidgets/web/_gallery.scss @@ -73,11 +73,18 @@ $gallery-screen-md: $screen-md; } .widget-gallery-filter, - .widget-gallery-empty, - .widget-gallery-pagination { + .widget-gallery-empty { flex: 1; } + &-top-bar { + container: widget-gallery-header / inline-size; + } + + &-footer { + container: widget-gallery-footer / inline-size; + } + /** Helper classes */ @@ -89,20 +96,30 @@ $gallery-screen-md: $screen-md; width: inherit; } -:where(.widget-gallery-footer-controls) { +:where(.widget-gallery-footer-controls, .widget-gallery-top-bar-controls) { display: flex; flex-flow: row nowrap; + align-items: center; } -:where(.widget-gallery-fc-start) { - margin-block: var(--spacing-medium); - padding-inline: var(--spacing-medium); +:where(.widget-gallery-fc-end, .widget-gallery-tb-end) { + display: flex; + justify-content: flex-end; + align-items: center; } -:where(.widget-gallery-fc-start, .widget-gallery-fc-middle, .widget-gallery-fc-end) { +:where(.widget-gallery-fc-start, .widget-gallery-tb-start, .widget-gallery-fc-end, .widget-gallery-tb-end) { flex-grow: 1; flex-basis: 33.33%; min-height: 20px; + height: 54px; + padding: var(--spacing-small) 0; +} + +:where(.widget-gallery-fc-start, .widget-gallery-tb-start) { + padding-inline: var(--spacing-medium); + display: flex; + align-items: center; } .widget-gallery-clear-selection { @@ -113,4 +130,33 @@ $gallery-screen-md: $screen-md; color: var(--link-color); padding: 0; display: inline-block; + + &:focus:not(:focus-visible) { + outline: none; + } + + &:focus-visible { + outline: 1px solid var(--brand-primary, $brand-primary); + outline-offset: 2px; + } +} + +@container widget-gallery-footer (width < 500px) { + .widget-gallery-footer-controls { + flex-direction: column; + :where(.widget-gallery-fc-start, .widget-gallery-fc-end, .widget-gallery-fc-middle) { + width: 100%; + justify-content: center; + } + } +} + +@container widget-gallery-header (width < 500px) { + .widget-gallery-top-bar-controls { + flex-direction: column-reverse; + :where(.widget-gallery-tb-start, .widget-gallery-tb-end) { + width: 100%; + justify-content: center; + } + } } diff --git a/packages/pluggableWidgets/datagrid-dropdown-filter-web/src/hocs/withParentProvidedEnumStore.tsx b/packages/pluggableWidgets/datagrid-dropdown-filter-web/src/hocs/withParentProvidedEnumStore.tsx index 9321eba3be..f54fe4aaae 100644 --- a/packages/pluggableWidgets/datagrid-dropdown-filter-web/src/hocs/withParentProvidedEnumStore.tsx +++ b/packages/pluggableWidgets/datagrid-dropdown-filter-web/src/hocs/withParentProvidedEnumStore.tsx @@ -22,7 +22,7 @@ export function withParentProvidedEnumStore

( function useEnumFilterAPI(): Result { const ctx = useFilterAPI(); - const slctAPI = useRef(undefined); + const slctAPI = useRef(undefined); if (ctx.hasError) { return error(ctx.error); diff --git a/packages/pluggableWidgets/datagrid-web/src/components/SelectionCounter.tsx b/packages/pluggableWidgets/datagrid-web/src/components/SelectionCounter.tsx index 5e4d32ba16..c39aad32bf 100644 --- a/packages/pluggableWidgets/datagrid-web/src/components/SelectionCounter.tsx +++ b/packages/pluggableWidgets/datagrid-web/src/components/SelectionCounter.tsx @@ -1,6 +1,5 @@ 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; diff --git a/packages/pluggableWidgets/datagrid-web/src/components/WidgetFooter.tsx b/packages/pluggableWidgets/datagrid-web/src/components/WidgetFooter.tsx index 563cf379e7..e7119421a2 100644 --- a/packages/pluggableWidgets/datagrid-web/src/components/WidgetFooter.tsx +++ b/packages/pluggableWidgets/datagrid-web/src/components/WidgetFooter.tsx @@ -8,7 +8,7 @@ type WidgetFooterProps = { loadMoreButtonCaption?: string; hasMoreItems: boolean; setPage?: (computePage: (prevPage: number) => number) => void; -} & JSX.IntrinsicElements["div"]; +} & React.JSX.IntrinsicElements["div"]; export function WidgetFooter(props: WidgetFooterProps): ReactElement | null { const { pagination, selectionCount, paginationType, loadMoreButtonCaption, hasMoreItems, setPage, ...rest } = props; diff --git a/packages/pluggableWidgets/gallery-web/CHANGELOG.md b/packages/pluggableWidgets/gallery-web/CHANGELOG.md index b495b5c31c..a325447d39 100644 --- a/packages/pluggableWidgets/gallery-web/CHANGELOG.md +++ b/packages/pluggableWidgets/gallery-web/CHANGELOG.md @@ -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.6.1] - 2025-10-14 ### Fixed diff --git a/packages/pluggableWidgets/gallery-web/src/Gallery.editorConfig.ts b/packages/pluggableWidgets/gallery-web/src/Gallery.editorConfig.ts index 10de4a8530..e12b6a9c14 100644 --- a/packages/pluggableWidgets/gallery-web/src/Gallery.editorConfig.ts +++ b/packages/pluggableWidgets/gallery-web/src/Gallery.editorConfig.ts @@ -19,7 +19,11 @@ export function getProperties(values: GalleryPreviewProps, defaultProperties: Pr } if (values.itemSelection !== "Multi") { - hidePropertiesIn(defaultProperties, values, ["keepSelection"]); + hidePropertiesIn(defaultProperties, values, [ + "keepSelection", + "selectionCountPosition", + "clearSelectionButtonLabel" + ]); } const usePersonalization = values.storeFilters || values.storeSort; diff --git a/packages/pluggableWidgets/gallery-web/src/Gallery.editorPreview.tsx b/packages/pluggableWidgets/gallery-web/src/Gallery.editorPreview.tsx index 02fece07c7..eb57de0e29 100644 --- a/packages/pluggableWidgets/gallery-web/src/Gallery.editorPreview.tsx +++ b/packages/pluggableWidgets/gallery-web/src/Gallery.editorPreview.tsx @@ -64,7 +64,7 @@ function Preview(props: GalleryPreviewProps): ReactElement { ); return ( -

+
}> ); }); diff --git a/packages/pluggableWidgets/gallery-web/src/Gallery.xml b/packages/pluggableWidgets/gallery-web/src/Gallery.xml index 7958540ecb..72e82eb550 100644 --- a/packages/pluggableWidgets/gallery-web/src/Gallery.xml +++ b/packages/pluggableWidgets/gallery-web/src/Gallery.xml @@ -37,6 +37,22 @@ Keep selection If enabled, selected items will stay selected unless cleared by the user or a Nanoflow. + + Show selection count + + + Top + Bottom + Off + + + + Clear selection label + Customize the label of the 'Clear section' button + + Clear selection + + Content placeholder diff --git a/packages/pluggableWidgets/gallery-web/src/components/Gallery.tsx b/packages/pluggableWidgets/gallery-web/src/components/Gallery.tsx index 3874d9a388..d40b6a1194 100644 --- a/packages/pluggableWidgets/gallery-web/src/components/Gallery.tsx +++ b/packages/pluggableWidgets/gallery-web/src/components/Gallery.tsx @@ -14,7 +14,7 @@ import { GalleryTopBar } from "./GalleryTopBar"; import { ListBox } from "./ListBox"; import { ListItem } from "./ListItem"; -import { PaginationEnum, ShowPagingButtonsEnum } from "typings/GalleryProps"; +import { PaginationEnum, SelectionCountPositionEnum, ShowPagingButtonsEnum } from "typings/GalleryProps"; import { LoadMore, LoadMoreButton as LoadMorePreview } from "../components/LoadMore"; import { ItemEventsController } from "../typings/ItemEventsController"; import { SelectionCounter } from "./SelectionCounter"; @@ -45,6 +45,7 @@ export interface GalleryProps { ariaLabelListBox?: string; ariaLabelItem?: (item: T) => string | undefined; preview?: boolean; + selectionCountPosition?: SelectionCountPositionEnum; // Helpers focusController: FocusTargetController; @@ -59,20 +60,18 @@ export interface GalleryProps { export function Gallery(props: GalleryProps): ReactElement { const { loadMoreButtonCaption = "Load more" } = props; const pagination = props.paging ? ( -
- props.setPage && props.setPage(() => page)} - nextPage={() => props.setPage && props.setPage(prev => prev + 1)} - numberOfItems={props.numberOfItems} - page={props.page} - pageSize={props.pageSize} - previousPage={() => props.setPage && props.setPage(prev => prev - 1)} - pagination={props.paginationType} - showPagingButtons={props.showPagingButtons} - /> -
+ props.setPage && props.setPage(() => page)} + nextPage={() => props.setPage && props.setPage(prev => prev + 1)} + numberOfItems={props.numberOfItems} + page={props.page} + pageSize={props.pageSize} + previousPage={() => props.setPage && props.setPage(prev => prev - 1)} + pagination={props.paginationType} + showPagingButtons={props.showPagingButtons} + /> ) : null; const showTopPagination = @@ -80,6 +79,14 @@ export function Gallery(props: GalleryProps): ReactElem const showBottomPagination = props.paging && (props.paginationPosition === "bottom" || props.paginationPosition === "both"); + const selectionCounter = + !props.preview && props.selectionCountPosition !== "off" ? ( + + ) : null; + + const showTopSelectionCounter = selectionCounter && props.selectionCountPosition === "top"; + const showBottomSelectionCounter = selectionCounter && props.selectionCountPosition === "bottom"; + return ( (props: GalleryProps): ReactElem selectable={false} data-focusindex={props.tabIndex || 0} > - {showTopPagination && pagination} + +
+ {showTopSelectionCounter && selectionCounter} + {showTopPagination &&
{pagination}
} +
+
{props.showHeader && {props.header}} {props.showRefreshIndicator ? : null} (props: GalleryProps): ReactElem ))}
-
{!props.preview && }
- {props.paginationType === "loadMore" && ( -
- {props.preview && {loadMoreButtonCaption}}{" "} - {!props.preview && {loadMoreButtonCaption}} -
- )} -
{showBottomPagination && pagination}
+ {showBottomSelectionCounter &&
{selectionCounter}
} + +
+ {showBottomPagination && pagination} + {props.paginationType === "loadMore" && + (props.preview ? ( + {loadMoreButtonCaption} + ) : ( + {loadMoreButtonCaption} + ))} +
diff --git a/packages/pluggableWidgets/gallery-web/src/components/SelectionCounter.tsx b/packages/pluggableWidgets/gallery-web/src/components/SelectionCounter.tsx index f5b69ee760..e311e5b834 100644 --- a/packages/pluggableWidgets/gallery-web/src/components/SelectionCounter.tsx +++ b/packages/pluggableWidgets/gallery-web/src/components/SelectionCounter.tsx @@ -2,15 +2,34 @@ import { If } from "@mendix/widget-plugin-component-kit/If"; import { observer } from "mobx-react-lite"; import { useGalleryRootScope } from "../helpers/root-context"; -export const SelectionCounter = observer(function SelectionCounter() { +type SelectionCounterLocation = "top" | "bottom" | undefined; + +export const SelectionCounter = observer(function SelectionCounter({ + location +}: { + location?: SelectionCounterLocation; +}) { const { selectionCountStore, itemSelectHelper } = useGalleryRootScope(); + const containerClass = location === "top" ? "widget-gallery-tb-start" : "widget-gallery-pb-start"; + + const clearButtonAriaLabel = `${selectionCountStore.clearButtonLabel} (${selectionCountStore.selectedCount} selected)`; + return ( - {selectionCountStore.displayCount} |  - +
+ + {selectionCountStore.displayCount} + +  |  + +
); }); diff --git a/packages/pluggableWidgets/gallery-web/src/components/__tests__/__snapshots__/Gallery.spec.tsx.snap b/packages/pluggableWidgets/gallery-web/src/components/__tests__/__snapshots__/Gallery.spec.tsx.snap index 293aded5c8..1bf1c40de9 100644 --- a/packages/pluggableWidgets/gallery-web/src/components/__tests__/__snapshots__/Gallery.spec.tsx.snap +++ b/packages/pluggableWidgets/gallery-web/src/components/__tests__/__snapshots__/Gallery.spec.tsx.snap @@ -8,7 +8,11 @@ exports[`Gallery DOM Structure renders correctly 1`] = ` >