Skip to content

Commit 98a84ba

Browse files
committed
feat: row col selection border lines
1 parent e7d8fce commit 98a84ba

File tree

9 files changed

+187
-27
lines changed

9 files changed

+187
-27
lines changed

packages/core/src/data-editor/data-editor.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ export interface DataEditorProps extends Props, Pick<DataGridSearchProps, "image
499499
readonly gridSelection?: GridSelection;
500500
/**
501501
* Emitted whenever the grid selection changes. Specifying
502-
* this function will make the grids selection controlled, so
502+
* this function will make the grid's selection controlled, so
503503
* so you will need to specify {@link gridSelection} as well. See
504504
* the "Controlled Selection" example for details.
505505
*
@@ -686,6 +686,22 @@ export interface DataEditorProps extends Props, Pick<DataGridSearchProps, "image
686686
* Allows overriding the default portal element.
687687
*/
688688
readonly portalElementRef?: React.RefObject<HTMLElement>;
689+
690+
/**
691+
* When true (default) draws accent-coloured grid lines around selected columns in the header. Set to false to
692+
* revert to the original behaviour where only the header background is accented.
693+
* @group Style
694+
* @defaultValue true
695+
*/
696+
readonly columnSelectionGridLines?: boolean;
697+
698+
/**
699+
* When true (default) draws accent-coloured grid lines around selected rows in the header. Set to false to
700+
* revert to the original behaviour where only the header background is accented.
701+
* @group Style
702+
* @defaultValue true
703+
*/
704+
readonly rowSelectionGridLines?: boolean;
689705
}
690706

691707
type ScrollToFn = (
@@ -892,6 +908,8 @@ const DataEditorImpl: React.ForwardRefRenderFunction<DataEditorRef, DataEditorPr
892908
scrollToActiveCell = true,
893909
drawFocusRing: drawFocusRingIn = true,
894910
portalElementRef,
911+
columnSelectionGridLines = false,
912+
rowSelectionGridLines = false,
895913
} = p;
896914

897915
const drawFocusRing = drawFocusRingIn === "no-editor" ? overlay === undefined : drawFocusRingIn;
@@ -4264,6 +4282,8 @@ const DataEditorImpl: React.ForwardRefRenderFunction<DataEditorRef, DataEditorPr
42644282
gridRef={gridRef}
42654283
getCellRenderer={getCellRenderer}
42664284
resizeIndicator={resizeIndicator}
4285+
columnSelectionGridLines={columnSelectionGridLines}
4286+
rowSelectionGridLines={rowSelectionGridLines}
42674287
/>
42684288
{renameGroupNode}
42694289
{overlay !== undefined && (
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import React from "react";
2+
import { DataEditorAll as DataEditor } from "../../data-editor-all.js";
3+
import {
4+
BeautifulWrapper,
5+
Description,
6+
MoreInfo,
7+
useMockDataGenerator,
8+
defaultProps,
9+
} from "../../data-editor/stories/utils.js";
10+
import { SimpleThemeWrapper } from "../../stories/story-utils.js";
11+
12+
export default {
13+
title: "Glide-Data-Grid/DataEditor Demos",
14+
15+
decorators: [
16+
(Story: React.ComponentType) => (
17+
<SimpleThemeWrapper>
18+
<BeautifulWrapper
19+
title="Column & Row Selection Grid Lines"
20+
description={
21+
<>
22+
<Description>
23+
Demonstrates the <code>columnSelectionGridLines</code> and
24+
<code>rowSelectionGridLines</code> props which control whether accent-coloured grid
25+
lines are drawn around selected columns and rows.
26+
</Description>
27+
<MoreInfo>
28+
Use the story controls to toggle the behaviours on and off.
29+
</MoreInfo>
30+
</>
31+
}>
32+
<Story />
33+
</BeautifulWrapper>
34+
</SimpleThemeWrapper>
35+
),
36+
],
37+
};
38+
39+
interface SelectionGridLineProps {
40+
columnSelectionGridLines: boolean;
41+
rowSelectionGridLines: boolean;
42+
}
43+
44+
export const SelectionGridLine: React.FC<SelectionGridLineProps> = p => {
45+
const { cols, getCellContent } = useMockDataGenerator(10);
46+
return (
47+
<DataEditor
48+
{...defaultProps}
49+
getCellContent={getCellContent}
50+
columns={cols}
51+
rows={1000}
52+
columnSelectionGridLines={p.columnSelectionGridLines}
53+
rowSelectionGridLines={p.rowSelectionGridLines}
54+
rowMarkers="both"
55+
/>
56+
);
57+
};
58+
59+
(SelectionGridLine as any).args = {
60+
columnSelectionGridLines: true,
61+
rowSelectionGridLines: true,
62+
};
63+
64+
(SelectionGridLine as any).argTypes = {
65+
columnSelectionGridLines: {
66+
control: {
67+
type: "boolean",
68+
},
69+
},
70+
rowSelectionGridLines: {
71+
control: {
72+
type: "boolean",
73+
},
74+
},
75+
};

packages/core/src/internal/data-grid-dnd/data-grid-dnd.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,8 @@ const DataGridDnd: React.FunctionComponent<DataGridDndProps> = p => {
439439
dragAndDropState={dragOffset}
440440
onMouseMoveRaw={onMouseMove}
441441
ref={gridRef}
442+
columnSelectionGridLines={p.columnSelectionGridLines}
443+
rowSelectionGridLines={p.rowSelectionGridLines}
442444
/>
443445
);
444446
};

packages/core/src/internal/data-grid-search/data-grid-search.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,8 @@ const DataGridSearch: React.FunctionComponent<DataGridSearchProps> = p => {
549549
smoothScrollX={p.smoothScrollX}
550550
smoothScrollY={p.smoothScrollY}
551551
resizeIndicator={p.resizeIndicator}
552+
columnSelectionGridLines={p.columnSelectionGridLines}
553+
rowSelectionGridLines={p.rowSelectionGridLines}
552554
/>
553555
{searchbox}
554556
</>

packages/core/src/internal/data-grid/data-grid.tsx

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,18 @@ export interface DataGridProps {
307307
* @group Style
308308
*/
309309
readonly resizeIndicator: "full" | "header" | "none" | undefined;
310+
311+
/** Enables accent-coloured grid lines for selected columns in the header.
312+
* @defaultValue false
313+
* @group Style
314+
*/
315+
readonly columnSelectionGridLines?: boolean;
316+
317+
/** Enables accent-coloured grid lines for selected rows in the header.
318+
* @defaultValue false
319+
* @group Style
320+
*/
321+
readonly rowSelectionGridLines?: boolean;
310322
}
311323

312324
type DamageUpdateList = readonly {
@@ -320,7 +332,11 @@ export interface DataGridRef {
320332
focus: () => void;
321333
getBounds: (col?: number, row?: number) => Rectangle | undefined;
322334
damage: (cells: DamageUpdateList) => void;
323-
getMouseArgsForPosition: (posX: number, posY: number, ev?: MouseEvent | TouchEvent) => GridMouseEventArgs | undefined;
335+
getMouseArgsForPosition: (
336+
posX: number,
337+
posY: number,
338+
ev?: MouseEvent | TouchEvent
339+
) => GridMouseEventArgs | undefined;
324340
}
325341

326342
const getRowData = (cell: InnerGridCell, getCellRenderer?: GetCellRendererCallback) => {
@@ -396,6 +412,8 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
396412
experimental,
397413
getCellRenderer,
398414
resizeIndicator = "full",
415+
columnSelectionGridLines = false,
416+
rowSelectionGridLines = false,
399417
} = p;
400418
const translateX = p.translateX ?? 0;
401419
const translateY = p.translateY ?? 0;
@@ -446,7 +464,10 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
446464
}, [cellYOffset, cellXOffset, translateX, translateY, enableFirefoxRescaling, enableSafariRescaling]);
447465

448466
const mappedColumns = useMappedColumns(columns, freezeColumns);
449-
const stickyX = React.useMemo(() => fixedShadowX ? getStickyWidth(mappedColumns, dragAndDropState) : 0,[mappedColumns, dragAndDropState, fixedShadowX]);
467+
const stickyX = React.useMemo(
468+
() => (fixedShadowX ? getStickyWidth(mappedColumns, dragAndDropState) : 0),
469+
[mappedColumns, dragAndDropState, fixedShadowX]
470+
);
450471

451472
// row: -1 === columnHeader, -2 === groupHeader
452473
const getBoundsForItem = React.useCallback(
@@ -829,6 +850,8 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
829850
getCellRenderer,
830851
minimumCellWidth,
831852
resizeIndicator,
853+
columnSelectionGridLines,
854+
rowSelectionGridLines,
832855
};
833856

834857
// This confusing bit of code due to some poor design. Long story short, the damage property is only used
@@ -895,6 +918,8 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
895918
getCellRenderer,
896919
minimumCellWidth,
897920
resizeIndicator,
921+
columnSelectionGridLines,
922+
rowSelectionGridLines,
898923
]);
899924

900925
const lastDrawRef = React.useRef(draw);
@@ -951,15 +976,15 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
951976
const cursor = isDragging
952977
? "grabbing"
953978
: canDrag || isResizing
954-
? "col-resize"
955-
: overFill || isFilling
956-
? "crosshair"
957-
: cursorOverride !== undefined
958-
? cursorOverride
959-
: headerHovered || clickableInnerCellHovered || editableBoolHovered || groupHeaderHovered
960-
? "pointer"
961-
: "default";
962-
979+
? "col-resize"
980+
: overFill || isFilling
981+
? "crosshair"
982+
: cursorOverride !== undefined
983+
? cursorOverride
984+
: headerHovered || clickableInnerCellHovered || editableBoolHovered || groupHeaderHovered
985+
? "pointer"
986+
: "default";
987+
963988
const style = React.useMemo(
964989
() => ({
965990
// width,
@@ -1716,7 +1741,7 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
17161741
}
17171742

17181743
return getMouseArgsForPosition(canvasRef.current, posX, posY, ev);
1719-
}
1744+
},
17201745
}),
17211746
[canvasRef, damage, getBoundsForItem]
17221747
);

packages/core/src/internal/data-grid/render/data-grid-render.lines.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,9 @@ export function drawGridLines(
294294
freezeTrailingRows: number,
295295
rows: number,
296296
theme: FullTheme,
297-
verticalOnly: boolean = false
297+
verticalOnly: boolean = false,
298+
selectedColumns?: CompactSelection,
299+
selectedRows?: CompactSelection
298300
) {
299301
if (spans !== undefined) {
300302
ctx.beginPath();
@@ -307,6 +309,8 @@ export function drawGridLines(
307309
}
308310
const hColor = theme.horizontalBorderColor ?? theme.borderColor;
309311
const vColor = theme.borderColor;
312+
const selectedVColor = theme.accentColor;
313+
const selectedHColor = theme.accentColor;
310314

311315
const { minX, maxX, minY, maxY } = getMinMaxXY(drawRegions, width, height);
312316

@@ -322,12 +326,20 @@ export function drawGridLines(
322326
x += c.width;
323327
const tx = c.sticky ? x : x + translateX;
324328
if (tx >= minX && tx <= maxX && verticalBorder(index + 1)) {
329+
const leftSelected = selectedColumns?.hasIndex(c.sourceIndex) ?? false;
330+
const rightSelected =
331+
index < effectiveCols.length - 1
332+
? selectedColumns?.hasIndex(effectiveCols[index + 1].sourceIndex) ?? false
333+
: false;
334+
const color = leftSelected !== rightSelected
335+
? selectedVColor
336+
: vColor;
325337
toDraw.push({
326338
x1: tx,
327339
y1: Math.max(groupHeaderHeight, minY),
328340
x2: tx,
329341
y2: Math.min(height, maxY),
330-
color: vColor,
342+
color,
331343
});
332344
}
333345
}
@@ -348,12 +360,25 @@ export function drawGridLines(
348360
const ty = y + translateY;
349361
if (ty >= minY && ty <= maxY - 1) {
350362
const rowTheme = getRowThemeOverride?.(row);
363+
364+
let color = rowTheme?.horizontalBorderColor ?? rowTheme?.borderColor ?? hColor;
365+
366+
if (selectedRows !== undefined) {
367+
const currentSelected = selectedRows.hasIndex(row);
368+
const prevSelected = row > 0 ? selectedRows.hasIndex(row - 1) : false;
369+
370+
// Accent the line if it is a boundary between selected and unselected rows.
371+
if (currentSelected !== prevSelected && (currentSelected || prevSelected)) {
372+
color = selectedHColor;
373+
}
374+
}
375+
351376
toDraw.push({
352377
x1: minX,
353378
y1: ty,
354379
x2: maxX,
355380
y2: ty,
356-
color: rowTheme?.horizontalBorderColor ?? rowTheme?.borderColor ?? hColor,
381+
color,
357382
});
358383
}
359384

packages/core/src/internal/data-grid/render/data-grid-render.ts

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,17 @@ export function drawGrid(arg: DrawGridArg, lastArg: DrawGridArg | undefined) {
268268
}
269269
}
270270
const drawHeaderTexture = () => {
271+
272+
// Draw the bottom border of the header.
273+
overlayCtx.beginPath();
274+
overlayCtx.moveTo(0, overlayHeight - 0.5);
275+
overlayCtx.lineTo(width, overlayHeight - 0.5);
276+
overlayCtx.strokeStyle = blend(
277+
theme.headerBottomBorderColor ?? theme.horizontalBorderColor ?? theme.borderColor,
278+
theme.bgHeader
279+
);
280+
overlayCtx.stroke();
281+
271282
drawGridHeaders(
272283
overlayCtx,
273284
effectiveCols,
@@ -308,17 +319,10 @@ export function drawGrid(arg: DrawGridArg, lastArg: DrawGridArg | undefined) {
308319
freezeTrailingRows,
309320
rows,
310321
theme,
311-
true
312-
);
313-
314-
overlayCtx.beginPath();
315-
overlayCtx.moveTo(0, overlayHeight - 0.5);
316-
overlayCtx.lineTo(width, overlayHeight - 0.5);
317-
overlayCtx.strokeStyle = blend(
318-
theme.headerBottomBorderColor ?? theme.horizontalBorderColor ?? theme.borderColor,
319-
theme.bgHeader
322+
true,
323+
arg.columnSelectionGridLines ? selection.columns : undefined,
324+
arg.rowSelectionGridLines ? selection.rows : undefined
320325
);
321-
overlayCtx.stroke();
322326

323327
if (mustDrawHighlightRingsOnHeader) {
324328
drawHighlightRings(
@@ -716,7 +720,10 @@ export function drawGrid(arg: DrawGridArg, lastArg: DrawGridArg | undefined) {
716720
verticalBorder,
717721
freezeTrailingRows,
718722
rows,
719-
theme
723+
theme,
724+
false,
725+
arg.columnSelectionGridLines ? selection.columns : undefined,
726+
arg.rowSelectionGridLines ? selection.rows : undefined
720727
);
721728

722729
highlightRedraw?.();

packages/core/src/internal/data-grid/render/draw-grid-arg.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,6 @@ export interface DrawGridArg {
7979
readonly getCellRenderer: GetCellRendererCallback;
8080
readonly minimumCellWidth: number;
8181
readonly resizeIndicator: "full" | "header" | "none";
82+
readonly columnSelectionGridLines: boolean;
83+
readonly rowSelectionGridLines: boolean;
8284
}

packages/core/src/internal/scrolling-data-grid/scrolling-data-grid.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,8 @@ const GridScroller: React.FunctionComponent<ScrollingDataGridProps> = p => {
339339
smoothScrollX={p.smoothScrollX}
340340
smoothScrollY={p.smoothScrollY}
341341
resizeIndicator={p.resizeIndicator}
342+
columnSelectionGridLines={p.columnSelectionGridLines}
343+
rowSelectionGridLines={p.rowSelectionGridLines}
342344
/>
343345
</InfiniteScroller>
344346
);

0 commit comments

Comments
 (0)