feat(grid): improve boolean checkbox styling for light and dark themes

This commit is contained in:
lxk955
2026-10-04 16:39:17 +08:00
committed by GitHub
parent 024dc757a8
commit 7b47b64391
2 changed files with 81 additions and 5 deletions
@@ -270,16 +270,17 @@ function alignCanvasPixel(value: number, dpr: number): number {
return Math.round(value * dpr) / dpr;
}
function drawBooleanCheckbox(ctx: CanvasRenderingContext2D, options: { drawX: number; y: number; colWidth: number; scaleX: number; scaleY: number; theme: DataGridPaintTheme; checked: boolean }): void {
export function drawBooleanCheckbox(ctx: CanvasRenderingContext2D, options: { drawX: number; y: number; colWidth: number; scaleX: number; scaleY: number; theme: DataGridPaintTheme; checked: boolean }): void {
const { drawX, y, colWidth, scaleX, scaleY, theme, checked } = options;
const size = BOOLEAN_CHECKBOX_SIZE;
const boxX = alignCanvasPixel(drawX + (colWidth - size) / 2, scaleX);
const boxY = alignCanvasPixel(y + (CANVAS_DATA_GRID_ROW_HEIGHT - size) / 2, scaleY);
ctx.lineWidth = 1;
ctx.fillStyle = theme.background;
ctx.fillRect(boxX, boxY, size, size);
if (checked) {
ctx.fillStyle = theme.primary;
ctx.fillRect(boxX, boxY, size, size);
ctx.strokeStyle = theme.background;
ctx.strokeStyle = theme.foreground;
ctx.strokeRect(boxX + 0.5, boxY + 0.5, size - 1, size - 1);
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(boxX + 3, boxY + size / 2);
+76 -1
View File
@@ -1,6 +1,6 @@
import { strict as assert } from "node:assert";
import { test } from "vitest";
import { canvasDataGridActionReservedWidth, fitCanvasText, resolveCanvasCellTextLayout, resolveCanvasDataGridRowBase, resolveCanvasDataGridRowFill } from "../../apps/desktop/src/lib/dataGrid/canvasDataGridRenderer.ts";
import { canvasDataGridActionReservedWidth, drawBooleanCheckbox, fitCanvasText, resolveCanvasCellTextLayout, resolveCanvasDataGridRowBase, resolveCanvasDataGridRowFill } from "../../apps/desktop/src/lib/dataGrid/canvasDataGridRenderer.ts";
import { DATA_GRID_DARK_STRIPED_ROW_BG, DATA_GRID_LIGHT_STRIPED_ROW_BG, resolveDataGridPaintTheme } from "../../apps/desktop/src/lib/dataGrid/dataGridPaintTheme.ts";
function measureContext(charWidth = 1): CanvasRenderingContext2D {
@@ -96,3 +96,78 @@ test("canvas row base respects stripedRows option", () => {
assert.equal(resolveCanvasDataGridRowBase(theme, newRow, { isActive: false, stripedRows: false }), "row-new");
assert.equal(resolveCanvasDataGridRowBase(theme, newRow, { isActive: false, stripedRows: true }), "row-new");
});
test("drawBooleanCheckbox renders checked and unchecked state with clean background and border", () => {
interface CanvasCall {
method: string;
args: unknown[];
}
const calls: CanvasCall[] = [];
const fakeCtx = {
lineWidth: 1,
fillStyle: "",
strokeStyle: "",
fillRect: (x: number, y: number, w: number, h: number) => {
calls.push({ method: "fillRect", args: [x, y, w, h] });
},
strokeRect: (x: number, y: number, w: number, h: number) => {
calls.push({ method: "strokeRect", args: [x, y, w, h] });
},
beginPath: () => {
calls.push({ method: "beginPath", args: [] });
},
moveTo: (x: number, y: number) => {
calls.push({ method: "moveTo", args: [x, y] });
},
lineTo: (x: number, y: number) => {
calls.push({ method: "lineTo", args: [x, y] });
},
stroke: () => {
calls.push({ method: "stroke", args: [] });
},
} as unknown as CanvasRenderingContext2D;
const theme = {
background: "#ffffff",
foreground: "#111111",
mutedForeground: "#888888",
primary: "#000000",
} as unknown as Parameters<typeof drawBooleanCheckbox>[1]["theme"];
// Unchecked state: clean background fill and muted border
calls.length = 0;
drawBooleanCheckbox(fakeCtx, {
drawX: 0,
y: 0,
colWidth: 60,
scaleX: 1,
scaleY: 1,
theme,
checked: false,
});
assert.equal(fakeCtx.fillStyle, "#ffffff");
assert.equal(fakeCtx.strokeStyle, "#888888");
assert.equal(fakeCtx.lineWidth, 1);
assert.ok(calls.some((c) => c.method === "fillRect"));
assert.ok(calls.some((c) => c.method === "strokeRect"));
assert.ok(!calls.some((c) => c.method === "stroke"));
// Checked state: clean background fill, foreground border, and checkmark stroke
calls.length = 0;
drawBooleanCheckbox(fakeCtx, {
drawX: 0,
y: 0,
colWidth: 60,
scaleX: 1,
scaleY: 1,
theme,
checked: true,
});
assert.equal(fakeCtx.fillStyle, "#ffffff");
assert.equal(fakeCtx.strokeStyle, "#111111");
assert.equal(fakeCtx.lineWidth, 1);
assert.ok(calls.some((c) => c.method === "fillRect"));
assert.ok(calls.some((c) => c.method === "strokeRect"));
assert.ok(calls.some((c) => c.method === "stroke"));
});