Skip to content

Commit 2845bea

Browse files
committed
refactor: rewire grid header props
1 parent 2d1dd23 commit 2845bea

File tree

9 files changed

+83
-153
lines changed

9 files changed

+83
-153
lines changed

packages/pluggableWidgets/datagrid-web/src/Datagrid.tsx

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ const DatagridRoot = observer((props: DatagridContainerProps): ReactElement => {
8585
)}
8686
headerTitle={props.filterSectionTitle?.value}
8787
headerContent={props.filtersPlaceholder}
88-
headerWrapperRenderer={useCallback((_columnIndex: number, header: ReactElement) => header, [])}
8988
id={useMemo(() => `DataGrid${generateUUID()}`, [])}
9089
numberOfItems={props.datasource.totalCount}
9190
onExportCancel={abortExport}
@@ -95,10 +94,6 @@ const DatagridRoot = observer((props: DatagridContainerProps): ReactElement => {
9594
styles={props.style}
9695
exporting={exportProgress.inProgress}
9796
processedRows={exportProgress.loaded}
98-
visibleColumns={columnsStore.visibleColumns}
99-
availableColumns={columnsStore.availableColumns}
100-
setIsResizing={(status: boolean) => columnsStore.setIsResizing(status)}
101-
columnsSwap={(moved, [target, placement]) => columnsStore.swapColumns(moved, [target, placement])}
10297
selectActionHelper={selectActionHelper}
10398
cellEventsController={cellEventsController}
10499
checkboxEventsController={checkboxEventsController}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { useConst } from "@mendix/widget-plugin-mobx-kit/react/useConst";
2+
import { Container } from "brandi";
3+
import { ContainerProvider } from "brandi-react";
4+
import { PropsWithChildren, ReactNode } from "react";
5+
import { CORE_TOKENS as CORE } from "../model/tokens";
6+
import { GridColumn } from "../typings/GridColumn";
7+
8+
/** Provider to bind & provider column store for children at runtime. */
9+
export function ColumnProvider(props: PropsWithChildren<{ column: GridColumn }>): ReactNode {
10+
const ct = useConst(() => {
11+
const container = new Container();
12+
container.bind(CORE.column).toConstant(props.column);
13+
return container;
14+
});
15+
16+
return <ContainerProvider container={ct}>{props.children} </ContainerProvider>;
17+
}

packages/pluggableWidgets/datagrid-web/src/components/GridHeader.tsx

Lines changed: 17 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,50 @@
1-
import { ReactElement, ReactNode, useCallback, useState } from "react";
2-
import { ColumnId, GridColumn } from "../typings/GridColumn";
1+
import { ReactElement, useState } from "react";
2+
import { useColumnsStore, useDatagridConfig } from "../model/hooks/injection-hooks";
3+
import { ColumnId } from "../typings/GridColumn";
34
import { CheckboxColumnHeader } from "./CheckboxColumnHeader";
5+
import { ColumnProvider } from "./ColumnProvider";
46
import { ColumnResizer } from "./ColumnResizer";
57
import { ColumnSelector } from "./ColumnSelector";
68
import { Header } from "./Header";
79
import { HeaderSkeletonLoader } from "./loader/HeaderSkeletonLoader";
810

9-
type GridHeaderProps = {
10-
availableColumns: GridColumn[];
11-
columns: GridColumn[];
12-
setIsResizing: (status: boolean) => void;
13-
columnsDraggable: boolean;
14-
columnsFilterable: boolean;
15-
columnsHidable: boolean;
16-
columnsResizable: boolean;
17-
columnsSortable: boolean;
18-
columnsSwap: (source: ColumnId, target: [ColumnId, "after" | "before"]) => void;
19-
filterRenderer: (renderWrapper: (children: ReactNode) => ReactElement, columnIndex: number) => ReactElement;
20-
headerWrapperRenderer: (columnIndex: number, header: ReactElement) => ReactElement;
21-
id: string;
22-
isLoading: boolean;
23-
preview?: boolean;
24-
};
25-
26-
export function GridHeader({
27-
availableColumns,
28-
columns,
29-
setIsResizing,
30-
columnsDraggable,
31-
columnsFilterable,
32-
columnsHidable,
33-
columnsResizable,
34-
columnsSortable,
35-
columnsSwap,
36-
filterRenderer,
37-
headerWrapperRenderer,
38-
id,
39-
isLoading,
40-
preview
41-
}: GridHeaderProps): ReactElement {
11+
export function GridHeader(): ReactElement {
12+
const { columnsHidable, id: gridId } = useDatagridConfig();
13+
const columnsStore = useColumnsStore();
14+
const columns = columnsStore.visibleColumns;
4215
const [dragOver, setDragOver] = useState<[ColumnId, "before" | "after"] | undefined>(undefined);
4316
const [isDragging, setIsDragging] = useState<[ColumnId | undefined, ColumnId, ColumnId | undefined] | undefined>();
4417

45-
const renderFilterWrapper = useCallback(
46-
(children: ReactNode) => (
47-
<div className="filter" style={{ pointerEvents: isDragging ? "none" : undefined }}>
48-
{children}
49-
</div>
50-
),
51-
[isDragging]
52-
);
53-
54-
if (isLoading) {
18+
if (!columnsStore.loaded) {
5519
return <HeaderSkeletonLoader size={columns.length} />;
5620
}
5721

5822
return (
5923
<div className="widget-datagrid-grid-head" role="rowgroup">
6024
<div key="headers_row" className="tr" role="row">
6125
<CheckboxColumnHeader key="headers_column_select_all" />
62-
{columns.map((column, index) =>
63-
headerWrapperRenderer(
64-
index,
26+
{columns.map(column => (
27+
<ColumnProvider column={column} key={`${column.columnId}`}>
6528
<Header
66-
key={`${column.columnId}`}
67-
className={`align-column-${column.alignment}`}
68-
gridId={id}
69-
column={column}
70-
draggable={columnsDraggable}
7129
dropTarget={dragOver}
72-
filterable={columnsFilterable}
73-
filterWidget={filterRenderer(renderFilterWrapper, column.columnIndex)}
74-
hidable={columnsHidable}
7530
isDragging={isDragging}
76-
preview={preview}
77-
resizable={columnsResizable && columns.at(-1) !== column}
7831
resizer={
7932
<ColumnResizer
80-
onResizeStart={() => setIsResizing(true)}
81-
onResizeEnds={() => setIsResizing(false)}
33+
onResizeStart={() => columnsStore.setIsResizing(true)}
34+
onResizeEnds={() => columnsStore.setIsResizing(false)}
8235
setColumnWidth={(width: number) => column.setSize(width)}
8336
/>
8437
}
85-
swapColumns={columnsSwap}
8638
setDropTarget={setDragOver}
8739
setIsDragging={setIsDragging}
88-
sortable={columnsSortable}
8940
/>
90-
)
91-
)}
41+
</ColumnProvider>
42+
))}
9243
{columnsHidable && (
9344
<ColumnSelector
9445
key="headers_column_selector"
95-
columns={availableColumns}
96-
id={id}
46+
columns={columnsStore.availableColumns}
47+
id={gridId}
9748
visibleLength={columns.length}
9849
/>
9950
)}

packages/pluggableWidgets/datagrid-web/src/components/Header.tsx

Lines changed: 31 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import classNames from "classnames";
12
import {
23
Dispatch,
34
DragEvent,
@@ -9,92 +10,83 @@ import {
910
SetStateAction,
1011
useCallback
1112
} from "react";
12-
import classNames from "classnames";
13+
import { FaArrowsAltV } from "./icons/FaArrowsAltV";
1314
import { FaLongArrowAltDown } from "./icons/FaLongArrowAltDown";
1415
import { FaLongArrowAltUp } from "./icons/FaLongArrowAltUp";
15-
import { FaArrowsAltV } from "./icons/FaArrowsAltV";
1616

17-
import { ColumnResizerProps } from "./ColumnResizer";
17+
import { useColumn, useColumnsStore, useDatagridConfig } from "../model/hooks/injection-hooks";
1818
import { ColumnId, GridColumn } from "../typings/GridColumn";
19+
import { ColumnResizerProps } from "./ColumnResizer";
1920

2021
export interface HeaderProps {
21-
className?: string;
22-
gridId: string;
23-
column: GridColumn;
24-
sortable: boolean;
25-
resizable: boolean;
26-
filterable: boolean;
27-
hidable: boolean;
28-
draggable: boolean;
29-
filterWidget?: ReactNode;
30-
preview?: boolean;
22+
isLast?: boolean;
3123
resizer: ReactElement<ColumnResizerProps>;
24+
3225
dropTarget?: [ColumnId, "before" | "after"];
3326
isDragging?: [ColumnId | undefined, ColumnId, ColumnId | undefined];
3427
setDropTarget: Dispatch<SetStateAction<[ColumnId, "before" | "after"] | undefined>>;
3528
setIsDragging: Dispatch<SetStateAction<[ColumnId | undefined, ColumnId, ColumnId | undefined] | undefined>>;
36-
swapColumns: (source: ColumnId, target: [ColumnId, "before" | "after"]) => void;
3729
}
3830

3931
export function Header(props: HeaderProps): ReactElement {
40-
const canSort = props.sortable && props.column.canSort;
41-
const canDrag = props.draggable && (props.column.canDrag ?? false);
32+
const { columnsFilterable, id: gridId } = useDatagridConfig();
33+
const columnsStore = useColumnsStore();
34+
const column = useColumn();
35+
const { canDrag, canSort } = column;
36+
4237
const draggableProps = useDraggable(
4338
canDrag,
44-
props.swapColumns,
39+
columnsStore.swapColumns.bind(columnsStore),
4540
props.dropTarget,
4641
props.setDropTarget,
4742
props.isDragging,
4843
props.setIsDragging
4944
);
5045

51-
const sortIcon = canSort ? getSortIcon(props.column) : null;
52-
const sortProps = canSort ? getSortProps(props.column) : null;
53-
const caption = props.column.header.trim();
46+
const sortIcon = canSort ? getSortIcon(column) : null;
47+
const sortProps = canSort ? getSortProps(column) : null;
48+
const caption = column.header.trim();
5449

5550
return (
5651
<div
57-
aria-sort={getAriaSort(canSort, props.column)}
58-
className={classNames(
59-
"th",
60-
{
61-
"hidden-column-preview":
62-
props.preview && (!props.column.isAvailable || (props.hidable && props.column.isHidden))
63-
},
64-
{
65-
[`drop-${props.dropTarget?.[1]}`]: props.column.columnId === props.dropTarget?.[0],
66-
dragging: props.column.columnId === props.isDragging?.[1],
67-
"dragging-over-self": props.column.columnId === props.isDragging?.[1] && !props.dropTarget
68-
}
69-
)}
52+
aria-sort={getAriaSort(canSort, column)}
53+
className={classNames("th", {
54+
[`drop-${props.dropTarget?.[1]}`]: column.columnId === props.dropTarget?.[0],
55+
dragging: column.columnId === props.isDragging?.[1],
56+
"dragging-over-self": column.columnId === props.isDragging?.[1] && !props.dropTarget
57+
})}
7058
role="columnheader"
7159
style={!canSort ? { cursor: "unset" } : undefined}
7260
title={caption}
73-
ref={ref => props.column.setHeaderElementRef(ref)}
74-
data-column-id={props.column.columnId}
61+
ref={ref => column.setHeaderElementRef(ref)}
62+
data-column-id={column.columnId}
7563
onDrop={draggableProps.onDrop}
7664
onDragEnter={draggableProps.onDragEnter}
7765
onDragOver={draggableProps.onDragOver}
7866
>
7967
<div
8068
className={classNames("column-container")}
81-
id={`${props.gridId}-column${props.column.columnId}`}
69+
id={`${gridId}-column${column.columnId}`}
8270
draggable={draggableProps.draggable}
8371
onDragStart={draggableProps.onDragStart}
8472
onDragEnd={draggableProps.onDragEnd}
8573
>
8674
<div
87-
className={classNames("column-header", { clickable: canSort }, props.className)}
75+
className={classNames("column-header", { clickable: canSort }, `align-column-${column.alignment}`)}
8876
style={{ pointerEvents: props.isDragging ? "none" : undefined }}
8977
{...sortProps}
9078
aria-label={canSort ? "sort " + caption : caption}
9179
>
9280
<span>{caption.length > 0 ? caption : "\u00a0"}</span>
9381
{sortIcon}
9482
</div>
95-
{props.filterable && props.filterWidget}
83+
{columnsFilterable && (
84+
<div className="filter" style={{ pointerEvents: props.isDragging ? "none" : undefined }}>
85+
{columnsStore.columnFilters[column.columnIndex]?.renderFilterWidgets()}
86+
</div>
87+
)}
9688
</div>
97-
{props.resizable && props.column.canResize && props.resizer}
89+
{column.canResize ? props.resizer : null}
9890
</div>
9991
);
10092
}

packages/pluggableWidgets/datagrid-web/src/components/Row.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import classNames from "classnames";
22
import { ObjectItem } from "mendix";
33
import { ReactElement } from "react";
4+
import { SelectActionHelper } from "../helpers/SelectActionHelper";
45
import { CellComponent, EventsController } from "../typings/CellComponent";
56
import { GridColumn } from "../typings/GridColumn";
6-
import { SelectorCell } from "./SelectorCell";
77
import { CheckboxCell } from "./CheckboxCell";
8-
import { SelectActionHelper } from "../helpers/SelectActionHelper";
8+
import { SelectorCell } from "./SelectorCell";
99

1010
export interface RowProps<C extends GridColumn> {
1111
className?: string;
@@ -14,23 +14,21 @@ export interface RowProps<C extends GridColumn> {
1414
item: ObjectItem;
1515
index: number;
1616
showSelectorCell?: boolean;
17-
selectableWrapper?: (column: number, children: ReactElement) => ReactElement;
1817
selectActionHelper: SelectActionHelper;
19-
preview: boolean;
2018
totalRows: number;
2119
clickable: boolean;
2220
eventsController: EventsController;
2321
}
2422

2523
export function Row<C extends GridColumn>(props: RowProps<C>): ReactElement {
26-
const { CellComponent: Cell, selectActionHelper, preview, totalRows, eventsController } = props;
24+
const { CellComponent: Cell, selectActionHelper, totalRows, eventsController } = props;
2725
const selected = selectActionHelper.isSelected(props.item);
2826
const ariaSelected = selectActionHelper.selectionType === "None" ? undefined : selected;
2927
const borderTop = props.index === 0;
3028

3129
return (
3230
<div
33-
className={classNames("tr", { "tr-selected": selected, "tr-preview": preview }, props.className)}
31+
className={classNames("tr", { "tr-selected": selected }, props.className)}
3432
role="row"
3533
aria-selected={ariaSelected}
3634
>
@@ -52,12 +50,12 @@ export function Row<C extends GridColumn>(props: RowProps<C>): ReactElement {
5250
columnIndex={selectActionHelper.showCheckboxColumn ? baseIndex + 1 : baseIndex}
5351
item={props.item}
5452
clickable={props.clickable}
55-
preview={preview}
53+
preview={false}
5654
eventsController={eventsController}
5755
/>
5856
);
5957

60-
return preview ? props.selectableWrapper?.(baseIndex, cell) : cell;
58+
return cell;
6159
})}
6260
{props.showSelectorCell && (
6361
<SelectorCell
Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
import { KeyNavProvider } from "@mendix/widget-plugin-grid/keyboard-navigation/context";
22
import { FocusTargetController } from "@mendix/widget-plugin-grid/keyboard-navigation/FocusTargetController";
33
import { ObjectItem } from "mendix";
4+
import { observer } from "mobx-react-lite";
45
import { ReactElement } from "react";
56
import { SelectActionHelper } from "../helpers/SelectActionHelper";
7+
import { useColumnsStore } from "../model/hooks/injection-hooks";
68
import { CellComponent, EventsController } from "../typings/CellComponent";
79
import { GridColumn } from "../typings/GridColumn";
810
import { Row } from "./Row";
911

1012
interface RowsRendererProps {
1113
Cell: CellComponent<GridColumn>;
12-
columns: GridColumn[];
1314
columnsHidable: boolean;
1415
eventsController: EventsController;
1516
focusController: FocusTargetController;
1617
interactive: boolean;
1718
preview: boolean;
1819
rowClass?: (item: ObjectItem) => string;
1920
rows: ObjectItem[];
20-
selectableWrapper?: (column: number, children: ReactElement) => ReactElement;
2121
selectActionHelper: SelectActionHelper;
2222
}
2323

24-
export function RowsRenderer(props: RowsRendererProps): ReactElement {
24+
export const RowsRenderer = observer(function RowsRenderer(props: RowsRendererProps): ReactElement {
25+
const { visibleColumns } = useColumnsStore();
2526
return (
2627
<KeyNavProvider focusController={props.focusController}>
2728
{props.rows.map((item, rowIndex) => {
@@ -30,19 +31,17 @@ export function RowsRenderer(props: RowsRendererProps): ReactElement {
3031
totalRows={props.rows.length}
3132
clickable={props.interactive}
3233
selectActionHelper={props.selectActionHelper}
33-
preview={props.preview}
3434
eventsController={props.eventsController}
3535
CellComponent={props.Cell}
3636
className={props.rowClass?.(item)}
37-
columns={props.columns}
37+
columns={visibleColumns}
3838
index={rowIndex}
3939
item={item}
4040
key={`row_${item.id}`}
4141
showSelectorCell={props.columnsHidable}
42-
selectableWrapper={props.selectableWrapper}
4342
/>
4443
);
4544
})}
4645
</KeyNavProvider>
4746
);
48-
}
47+
});

0 commit comments

Comments
 (0)