Skip to content

Commit bb74b16

Browse files
committed
refactor: standardize use of brandi
1 parent e90088b commit bb74b16

File tree

9 files changed

+333
-191
lines changed

9 files changed

+333
-191
lines changed

packages/modules/data-widgets/src/themesource/datawidgets/web/_datagrid.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,10 @@ $root: ".widget-datagrid";
149149
}
150150
}
151151

152+
.drag-handle + .column-caption {
153+
padding-inline-start: 4px;
154+
}
155+
152156
&:focus:not(:focus-visible) {
153157
outline: none;
154158
}
Lines changed: 20 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -1,164 +1,59 @@
11
import classNames from "classnames";
2-
import {
3-
DragEvent,
4-
DragEventHandler,
5-
HTMLAttributes,
6-
KeyboardEvent,
7-
MouseEvent,
8-
ReactElement,
9-
ReactNode,
10-
useMemo
11-
} from "react";
12-
import { FaArrowsAltV } from "./icons/FaArrowsAltV";
13-
import { FaLongArrowAltDown } from "./icons/FaLongArrowAltDown";
14-
import { FaLongArrowAltUp } from "./icons/FaLongArrowAltUp";
15-
16-
import ColumnHeader from "./ColumnHeader";
17-
18-
import { useColumn, useColumnsStore, useDatagridConfig, useHeaderDragDrop } from "../model/hooks/injection-hooks";
19-
import { GridColumn } from "../typings/GridColumn";
2+
import { ReactElement } from "react";
3+
import { ColumnHeader } from "./ColumnHeader";
4+
import { useColumn, useColumnsStore, useDatagridConfig, useColumnHeaderVM } from "../model/hooks/injection-hooks";
205
import { ColumnResizerProps } from "./ColumnResizer";
21-
import { ColumnHeaderViewModel } from "../features/column/ColumnHeader.viewModel";
226
import { observer } from "mobx-react-lite";
237

248
export interface ColumnContainerProps {
259
isLast?: boolean;
2610
resizer: ReactElement<ColumnResizerProps>;
2711
}
28-
interface DragHandleProps {
29-
draggable: boolean;
30-
onDragStart?: DragEventHandler<HTMLSpanElement>;
31-
onDragEnd?: DragEventHandler<HTMLSpanElement>;
32-
}
3312

3413
export const ColumnContainer = observer(function ColumnContainer(props: ColumnContainerProps): ReactElement {
3514
const { columnsFilterable, id: gridId } = useDatagridConfig();
36-
const columnsStore = useColumnsStore();
37-
const column = useColumn();
38-
const { canDrag, canSort } = column;
15+
const { columnFilters } = useColumnsStore();
16+
const { canSort, columnId, setHeaderElementRef, columnIndex, canResize, sortDir, header } = useColumn();
17+
const { draggableProps, dropTarget, dragging } = useColumnHeaderVM();
3918

40-
const headerDragDropStore = useHeaderDragDrop();
41-
const columnHeaderVM = useMemo(
42-
() =>
43-
new ColumnHeaderViewModel({
44-
dndStore: headerDragDropStore,
45-
columnsStore,
46-
columnsDraggable: canDrag
47-
}),
48-
[headerDragDropStore, columnsStore, canDrag]
49-
);
50-
const draggableProps = columnHeaderVM.draggableProps;
51-
const dropTarget = columnHeaderVM.dropTarget;
52-
const isDragging = columnHeaderVM.dragging;
53-
54-
const sortProps = canSort ? getSortProps(column) : null;
55-
const caption = column.header.trim();
19+
const caption = header.trim();
5620

5721
return (
5822
<div
59-
aria-sort={getAriaSort(canSort, column)}
23+
aria-sort={getAriaSort(canSort, sortDir)}
6024
className={classNames("th", {
61-
[`drop-${dropTarget?.[1]}`]: column.columnId === dropTarget?.[0],
62-
dragging: column.columnId === isDragging?.[1],
63-
"dragging-over-self": column.columnId === isDragging?.[1] && !dropTarget
25+
[`drop-${dropTarget?.[1]}`]: columnId === dropTarget?.[0],
26+
dragging: columnId === dragging?.[1],
27+
"dragging-over-self": columnId === dragging?.[1] && !dropTarget
6428
})}
6529
role="columnheader"
6630
style={!canSort ? { cursor: "unset" } : undefined}
6731
title={caption}
68-
ref={ref => column.setHeaderElementRef(ref)}
69-
data-column-id={column.columnId}
32+
ref={ref => setHeaderElementRef(ref)}
33+
data-column-id={columnId}
7034
onDrop={draggableProps.onDrop}
7135
onDragEnter={draggableProps.onDragEnter}
7236
onDragOver={draggableProps.onDragOver}
7337
>
74-
<div className={classNames("column-container")} id={`${gridId}-column${column.columnId}`}>
75-
<ColumnHeader
76-
sortProps={sortProps}
77-
canSort={canSort}
78-
caption={caption}
79-
isDragging={isDragging}
80-
columnAlignment={column.alignment}
81-
>
82-
{draggableProps.draggable && (
83-
<DragHandle
84-
draggable={draggableProps.draggable}
85-
onDragStart={draggableProps.onDragStart}
86-
onDragEnd={draggableProps.onDragEnd}
87-
/>
88-
)}
89-
<span style={draggableProps.draggable ? { paddingInlineStart: "4px" } : undefined}>
90-
{caption.length > 0 ? caption : "\u00a0"}
91-
</span>
92-
{canSort ? <SortIcon /> : null}
93-
</ColumnHeader>
38+
<div className={classNames("column-container")} id={`${gridId}-column${columnId}`}>
39+
<ColumnHeader />
9440
{columnsFilterable && (
95-
<div className="filter" style={{ pointerEvents: isDragging ? "none" : undefined }}>
96-
{columnsStore.columnFilters[column.columnIndex]?.renderFilterWidgets()}
41+
<div className="filter" style={{ pointerEvents: dragging ? "none" : undefined }}>
42+
{columnFilters[columnIndex]?.renderFilterWidgets()}
9743
</div>
9844
)}
9945
</div>
100-
{column.canResize ? props.resizer : null}
46+
{canResize ? props.resizer : null}
10147
</div>
10248
);
10349
});
10450

105-
function DragHandle({ draggable, onDragStart, onDragEnd }: DragHandleProps): ReactElement {
106-
const handleMouseDown = (e: MouseEvent<HTMLSpanElement>): void => {
107-
// Only stop propagation, don't prevent default - we need default for drag to work
108-
e.stopPropagation();
109-
};
110-
111-
const handleClick = (e: MouseEvent<HTMLSpanElement>): void => {
112-
// Stop click events from bubbling to prevent sorting
113-
e.stopPropagation();
114-
e.preventDefault();
115-
};
116-
117-
const handleDragStart = (e: DragEvent<HTMLSpanElement>): void => {
118-
// Don't stop propagation here - let the drag start properly
119-
if (onDragStart) {
120-
onDragStart(e);
121-
}
122-
};
123-
124-
const handleDragEnd = (e: DragEvent<HTMLSpanElement>): void => {
125-
if (onDragEnd) {
126-
onDragEnd(e);
127-
}
128-
};
129-
130-
return (
131-
<span
132-
className="drag-handle"
133-
draggable={draggable}
134-
onDragStart={handleDragStart}
135-
onDragEnd={handleDragEnd}
136-
onMouseDown={handleMouseDown}
137-
onClick={handleClick}
138-
>
139-
140-
</span>
141-
);
142-
}
143-
144-
function SortIcon(): ReactNode {
145-
const column = useColumn();
146-
switch (column.sortDir) {
147-
case "asc":
148-
return <FaLongArrowAltUp />;
149-
case "desc":
150-
return <FaLongArrowAltDown />;
151-
default:
152-
return <FaArrowsAltV />;
153-
}
154-
}
155-
156-
function getAriaSort(canSort: boolean, column: GridColumn): "ascending" | "descending" | "none" | undefined {
51+
function getAriaSort(canSort: boolean, sortDir: string | undefined): "ascending" | "descending" | "none" | undefined {
15752
if (!canSort) {
15853
return undefined;
15954
}
16055

161-
switch (column.sortDir) {
56+
switch (sortDir) {
16257
case "asc":
16358
return "ascending";
16459
case "desc":
@@ -167,19 +62,3 @@ function getAriaSort(canSort: boolean, column: GridColumn): "ascending" | "desce
16762
return "none";
16863
}
16964
}
170-
171-
function getSortProps(column: GridColumn): HTMLAttributes<HTMLDivElement> {
172-
return {
173-
onClick: () => {
174-
column.toggleSort();
175-
},
176-
onKeyDown: (e: KeyboardEvent<HTMLDivElement>) => {
177-
if (e.key === "Enter" || e.key === " ") {
178-
e.preventDefault();
179-
column.toggleSort();
180-
}
181-
},
182-
role: "button",
183-
tabIndex: 0
184-
};
185-
}
Lines changed: 97 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,106 @@
11
import classNames from "classnames";
2-
import { HTMLAttributes, ReactElement, ReactNode } from "react";
3-
4-
export interface ColumnHeaderProps {
5-
children?: ReactNode;
6-
sortProps?: HTMLAttributes<HTMLDivElement> | null;
7-
canSort: boolean;
8-
caption: string;
9-
isDragging?: [string | undefined, string, string | undefined] | undefined;
10-
columnAlignment?: "left" | "center" | "right";
2+
import { DragEventHandler, DragEvent, HTMLAttributes, KeyboardEvent, MouseEvent, ReactElement, ReactNode } from "react";
3+
import { FaArrowsAltV } from "./icons/FaArrowsAltV";
4+
import { FaLongArrowAltDown } from "./icons/FaLongArrowAltDown";
5+
import { FaLongArrowAltUp } from "./icons/FaLongArrowAltUp";
6+
import { useColumn, useColumnHeaderVM } from "../model/hooks/injection-hooks";
7+
import { observer } from "mobx-react-lite";
8+
9+
interface DragHandleProps {
10+
draggable: boolean;
11+
onDragStart?: DragEventHandler<HTMLSpanElement>;
12+
onDragEnd?: DragEventHandler<HTMLSpanElement>;
1113
}
1214

13-
export default function ColumnHeader(props: ColumnHeaderProps): ReactElement {
15+
export const ColumnHeader = observer(function ColumnHeader(): ReactElement {
16+
const { draggableProps, dragging } = useColumnHeaderVM();
17+
const { header, canSort, alignment, toggleSort } = useColumn();
18+
const caption = header.trim();
19+
const sortProps = canSort ? getSortProps(toggleSort) : null;
20+
1421
return (
1522
<div
16-
className={classNames(
17-
"column-header",
18-
{ clickable: props.canSort },
19-
`align-column-${props.columnAlignment}`
20-
)}
21-
style={{ pointerEvents: props.isDragging ? "none" : undefined }}
22-
{...props.sortProps}
23-
aria-label={props.canSort ? "sort " + props.caption : props.caption}
23+
className={classNames("column-header", { clickable: canSort }, `align-column-${alignment}`)}
24+
style={{ pointerEvents: dragging ? "none" : undefined }}
25+
{...sortProps}
26+
aria-label={canSort ? "sort " + caption : caption}
2427
>
25-
{props.children}
28+
{draggableProps.draggable && (
29+
<DragHandle
30+
draggable={draggableProps.draggable}
31+
onDragStart={draggableProps.onDragStart}
32+
onDragEnd={draggableProps.onDragEnd}
33+
/>
34+
)}
35+
<span className="column-caption">{caption.length > 0 ? caption : "\u00a0"}</span>
36+
{canSort ? <SortIcon /> : null}
2637
</div>
2738
);
39+
});
40+
41+
function DragHandle({ draggable, onDragStart, onDragEnd }: DragHandleProps): ReactElement {
42+
const handleMouseDown = (e: MouseEvent<HTMLSpanElement>): void => {
43+
// Only stop propagation, don't prevent default - we need default for drag to work
44+
e.stopPropagation();
45+
};
46+
47+
const handleClick = (e: MouseEvent<HTMLSpanElement>): void => {
48+
// Stop click events from bubbling to prevent sorting
49+
e.stopPropagation();
50+
e.preventDefault();
51+
};
52+
53+
const handleDragStart = (e: DragEvent<HTMLSpanElement>): void => {
54+
// Don't stop propagation here - let the drag start properly
55+
if (onDragStart) {
56+
onDragStart(e);
57+
}
58+
};
59+
60+
const handleDragEnd = (e: DragEvent<HTMLSpanElement>): void => {
61+
if (onDragEnd) {
62+
onDragEnd(e);
63+
}
64+
};
65+
66+
return (
67+
<span
68+
className="drag-handle"
69+
draggable={draggable}
70+
onDragStart={handleDragStart}
71+
onDragEnd={handleDragEnd}
72+
onMouseDown={handleMouseDown}
73+
onClick={handleClick}
74+
>
75+
76+
</span>
77+
);
78+
}
79+
80+
function SortIcon(): ReactNode {
81+
const column = useColumn();
82+
switch (column.sortDir) {
83+
case "asc":
84+
return <FaLongArrowAltUp />;
85+
case "desc":
86+
return <FaLongArrowAltDown />;
87+
default:
88+
return <FaArrowsAltV />;
89+
}
90+
}
91+
92+
function getSortProps(toggleSort: () => void): HTMLAttributes<HTMLDivElement> {
93+
return {
94+
onClick: () => {
95+
toggleSort();
96+
},
97+
onKeyDown: (e: KeyboardEvent<HTMLDivElement>) => {
98+
if (e.key === "Enter" || e.key === " ") {
99+
e.preventDefault();
100+
toggleSort();
101+
}
102+
},
103+
role: "button",
104+
tabIndex: 0
105+
};
28106
}

0 commit comments

Comments
 (0)