Skip to content

Commit da42bde

Browse files
committed
feat: draw grid lines for selected rows cols
1 parent e7d8fce commit da42bde

File tree

8 files changed

+191
-6
lines changed

8 files changed

+191
-6
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

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

Lines changed: 11 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,14 @@ 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;
689697
}
690698

691699
type ScrollToFn = (
@@ -892,6 +900,7 @@ const DataEditorImpl: React.ForwardRefRenderFunction<DataEditorRef, DataEditorPr
892900
scrollToActiveCell = true,
893901
drawFocusRing: drawFocusRingIn = true,
894902
portalElementRef,
903+
columnSelectionGridLines = true,
895904
} = p;
896905

897906
const drawFocusRing = drawFocusRingIn === "no-editor" ? overlay === undefined : drawFocusRingIn;
@@ -4264,6 +4273,7 @@ const DataEditorImpl: React.ForwardRefRenderFunction<DataEditorRef, DataEditorPr
42644273
gridRef={gridRef}
42654274
getCellRenderer={getCellRenderer}
42664275
resizeIndicator={resizeIndicator}
4276+
columnSelectionGridLines={columnSelectionGridLines}
42674277
/>
42684278
{renameGroupNode}
42694279
{overlay !== undefined && (
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
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 GridLineDemoProps {
40+
columnSelectionGridLines: boolean;
41+
rowSelectionGridLines: boolean;
42+
}
43+
44+
export const GridLineDemo: React.FC<GridLineDemoProps> = p => {
45+
const { cols, getCellContent } = useMockDataGenerator(10);
46+
47+
return (
48+
<DataEditor
49+
{...defaultProps}
50+
getCellContent={getCellContent}
51+
columns={cols}
52+
rows={1000}
53+
columnSelectionGridLines={p.columnSelectionGridLines}
54+
rowSelectionGridLines={p.rowSelectionGridLines}
55+
rowMarkers="both"
56+
/>
57+
);
58+
};
59+
60+
(GridLineDemo as any).args = {
61+
columnSelectionGridLines: true,
62+
rowSelectionGridLines: true,
63+
};
64+
65+
(GridLineDemo as any).argTypes = {
66+
columnSelectionGridLines: {
67+
control: {
68+
type: "boolean",
69+
},
70+
},
71+
rowSelectionGridLines: {
72+
control: {
73+
type: "boolean",
74+
},
75+
},
76+
};

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

Lines changed: 18 additions & 0 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 {
@@ -396,6 +408,8 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
396408
experimental,
397409
getCellRenderer,
398410
resizeIndicator = "full",
411+
columnSelectionGridLines = true,
412+
rowSelectionGridLines = true,
399413
} = p;
400414
const translateX = p.translateX ?? 0;
401415
const translateY = p.translateY ?? 0;
@@ -829,6 +843,8 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
829843
getCellRenderer,
830844
minimumCellWidth,
831845
resizeIndicator,
846+
columnSelectionGridLines,
847+
rowSelectionGridLines,
832848
};
833849

834850
// This confusing bit of code due to some poor design. Long story short, the damage property is only used
@@ -895,6 +911,8 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
895911
getCellRenderer,
896912
minimumCellWidth,
897913
resizeIndicator,
914+
columnSelectionGridLines,
915+
rowSelectionGridLines,
898916
]);
899917

900918
const lastDrawRef = React.useRef(draw);

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,13 @@ export function drawGridHeaders(
9191
const xOffset = c.sourceIndex === 0 ? 0 : 1;
9292

9393
if (selected) {
94+
// Fill the header background for selected columns. We intentionally skip drawing
95+
// a manual border here – the vertical grid lines will be recoloured to the accent
96+
// shade later in drawGridLines so we don’t end up with double-width accent bars
97+
// when multiple adjacent columns are selected.
9498
ctx.fillStyle = bgFillStyle;
9599
ctx.fillRect(x + xOffset, y, c.width - xOffset, headerHeight);
100+
96101
} else if (hasSelectedCell || hover > 0) {
97102
ctx.beginPath();
98103
ctx.rect(x + xOffset, y, c.width - xOffset, headerHeight);

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

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,10 @@ export function drawGridLines(
294294
freezeTrailingRows: number,
295295
rows: number,
296296
theme: FullTheme,
297-
verticalOnly: boolean = false
297+
verticalOnly: boolean = false,
298+
selectedColumns?: CompactSelection,
299+
accentInner: boolean = false,
300+
selectedRows?: CompactSelection
298301
) {
299302
if (spans !== undefined) {
300303
ctx.beginPath();
@@ -307,6 +310,8 @@ export function drawGridLines(
307310
}
308311
const hColor = theme.horizontalBorderColor ?? theme.borderColor;
309312
const vColor = theme.borderColor;
313+
const selectedVColor = theme.accentColor;
314+
const selectedHColor = theme.accentColor;
310315

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

@@ -322,12 +327,25 @@ export function drawGridLines(
322327
x += c.width;
323328
const tx = c.sticky ? x : x + translateX;
324329
if (tx >= minX && tx <= maxX && verticalBorder(index + 1)) {
330+
const leftSelected = selectedColumns?.hasIndex(c.sourceIndex) ?? false;
331+
const rightSelected =
332+
index < effectiveCols.length - 1
333+
? selectedColumns?.hasIndex(effectiveCols[index + 1].sourceIndex) ?? false
334+
: false;
335+
console.log("leftSelected", {leftSelected, rightSelected, selectedColumns});
336+
const color = accentInner
337+
? leftSelected || rightSelected
338+
? selectedVColor
339+
: vColor
340+
: leftSelected !== rightSelected
341+
? selectedVColor
342+
: vColor;
325343
toDraw.push({
326344
x1: tx,
327345
y1: Math.max(groupHeaderHeight, minY),
328346
x2: tx,
329347
y2: Math.min(height, maxY),
330-
color: vColor,
348+
color,
331349
});
332350
}
333351
}
@@ -348,12 +366,25 @@ export function drawGridLines(
348366
const ty = y + translateY;
349367
if (ty >= minY && ty <= maxY - 1) {
350368
const rowTheme = getRowThemeOverride?.(row);
369+
370+
let color = rowTheme?.horizontalBorderColor ?? rowTheme?.borderColor ?? hColor;
371+
372+
if (selectedRows !== undefined) {
373+
const currentSelected = selectedRows.hasIndex(row);
374+
const prevSelected = row > 0 ? selectedRows.hasIndex(row - 1) : false;
375+
376+
// Accent the line if it is a boundary between selected and unselected rows.
377+
if (currentSelected !== prevSelected && (currentSelected || prevSelected)) {
378+
color = selectedHColor;
379+
}
380+
}
381+
351382
toDraw.push({
352383
x1: minX,
353384
y1: ty,
354385
x2: maxX,
355386
y2: ty,
356-
color: rowTheme?.horizontalBorderColor ?? rowTheme?.borderColor ?? hColor,
387+
color,
357388
});
358389
}
359390

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

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,10 @@ export function drawGrid(arg: DrawGridArg, lastArg: DrawGridArg | undefined) {
308308
freezeTrailingRows,
309309
rows,
310310
theme,
311-
true
311+
true,
312+
arg.columnSelectionGridLines ? selection.columns : undefined,
313+
false,
314+
arg.rowSelectionGridLines ? selection.rows : undefined
312315
);
313316

314317
overlayCtx.beginPath();
@@ -320,6 +323,39 @@ export function drawGrid(arg: DrawGridArg, lastArg: DrawGridArg | undefined) {
320323
);
321324
overlayCtx.stroke();
322325

326+
// Overdraw the bottom border with the accent colour for each selected column so
327+
// the vertical accent grid lines visually connect with the header. We draw after
328+
// the default grey stroke so the accent sits on top.
329+
if (arg.columnSelectionGridLines && selection.columns.length > 0) {
330+
overlayCtx.beginPath();
331+
let xCursor = 0;
332+
for (let index = 0; index < effectiveCols.length; index++) {
333+
const col = effectiveCols[index];
334+
const isSelected = selection.columns.hasIndex(col.sourceIndex);
335+
336+
// Check for left and right edge.
337+
338+
const leftSelected = selection.columns?.hasIndex(col.sourceIndex) ?? false;
339+
const rightSelected =
340+
index < effectiveCols.length - 1
341+
? selection.columns?.hasIndex(effectiveCols[index + 1].sourceIndex) ?? false
342+
: false;
343+
344+
console.log("col", index, isSelected, leftSelected, rightSelected);
345+
346+
const offset = col.sourceIndex === 0 ? 0 : 1;
347+
const startX = xCursor + offset - (leftSelected ? 1 : 0);
348+
const endX = xCursor + col.width + 1;
349+
if (isSelected) {
350+
overlayCtx.moveTo(startX, totalHeaderHeight + 0.5);
351+
overlayCtx.lineTo(endX, totalHeaderHeight + 0.5);
352+
}
353+
xCursor += col.width;
354+
}
355+
overlayCtx.strokeStyle = theme.accentColor;
356+
overlayCtx.stroke();
357+
}
358+
323359
if (mustDrawHighlightRingsOnHeader) {
324360
drawHighlightRings(
325361
overlayCtx,
@@ -699,6 +735,8 @@ export function drawGrid(arg: DrawGridArg, lastArg: DrawGridArg | undefined) {
699735
theme
700736
);
701737

738+
console.log("selection", selection);
739+
702740
drawGridLines(
703741
targetCtx,
704742
effectiveCols,
@@ -716,7 +754,11 @@ export function drawGrid(arg: DrawGridArg, lastArg: DrawGridArg | undefined) {
716754
verticalBorder,
717755
freezeTrailingRows,
718756
rows,
719-
theme
757+
theme,
758+
false,
759+
(arg.columnSelectionGridLines ? selection.columns : undefined),
760+
false,
761+
(arg.rowSelectionGridLines ? selection.rows : undefined)
720762
);
721763

722764
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
}

0 commit comments

Comments
 (0)