Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Theme options for edit hover indicators #926

Merged
merged 3 commits into from Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 11 additions & 2 deletions packages/core/src/cells/number-cell.tsx
Expand Up @@ -3,6 +3,7 @@ import * as React from "react";
import { drawTextCell, prepTextCell } from "../internal/data-grid/render/data-grid-lib.js";
import { GridCellKind, type NumberCell } from "../internal/data-grid/data-grid-types.js";
import type { InternalCellRenderer } from "./cell-types.js";
import { drawEditHoverIndicator } from "../internal/data-grid/render/draw-edit-hover-indicator.js";

const NumberOverlayEditor = React.lazy(
async () => await import("../internal/data-grid-overlay-editor/private/number-overlay-editor.js")
Expand All @@ -11,11 +12,19 @@ const NumberOverlayEditor = React.lazy(
export const numberCellRenderer: InternalCellRenderer<NumberCell> = {
getAccessibilityString: c => c.data?.toString() ?? "",
kind: GridCellKind.Number,
needsHover: false,
needsHover: cell => cell.hoverEffect === true,
needsHoverPosition: false,
useLabel: true,
drawPrep: prepTextCell,
draw: a => drawTextCell(a, a.cell.displayData, a.cell.contentAlign),
draw: a => {
const { hoverAmount, cell, ctx, theme, rect, overrideCursor } = a;
const { hoverEffect, displayData, hoverEffectTheme } = cell;

if (hoverEffect === true && hoverAmount > 0) {
drawEditHoverIndicator(ctx, theme, hoverEffectTheme, displayData, rect, hoverAmount, overrideCursor);
}
drawTextCell(a, a.cell.displayData, a.cell.contentAlign);
},
measure: (ctx, cell, theme) => ctx.measureText(cell.displayData).width + theme.cellHorizontalPadding * 2,
onDelete: c => ({
...c,
Expand Down
37 changes: 4 additions & 33 deletions packages/core/src/cells/text-cell.tsx
@@ -1,15 +1,10 @@
/* eslint-disable react/display-name */
import * as React from "react";
import { GrowingEntry } from "../internal/growing-entry/growing-entry.js";
import {
drawTextCell,
measureTextCached,
prepTextCell,
roundedRect,
} from "../internal/data-grid/render/data-grid-lib.js";
import { drawTextCell, prepTextCell } from "../internal/data-grid/render/data-grid-lib.js";
import { GridCellKind, type TextCell } from "../internal/data-grid/data-grid-types.js";
import type { InternalCellRenderer } from "./cell-types.js";
import { withAlpha } from "../internal/data-grid/color-parser.js";
import { drawEditHoverIndicator } from "../internal/data-grid/render/draw-edit-hover-indicator.js";

export const textCellRenderer: InternalCellRenderer<TextCell> = {
getAccessibilityString: c => c.data?.toString() ?? "",
Expand All @@ -20,33 +15,9 @@ export const textCellRenderer: InternalCellRenderer<TextCell> = {
useLabel: true,
draw: a => {
const { cell, hoverAmount, hyperWrapping, ctx, rect, theme, overrideCursor } = a;
const { displayData, contentAlign, hoverEffect, allowWrapping } = cell;
const { displayData, contentAlign, hoverEffect, allowWrapping, hoverEffectTheme } = cell;
if (hoverEffect === true && hoverAmount > 0) {
ctx.textBaseline = "alphabetic";
const padX = theme.cellHorizontalPadding;
const padY = theme.cellVerticalPadding;
const m = measureTextCached(displayData, ctx, theme.baseFontFull, "alphabetic");
const maxH = rect.height - padY;
const h = Math.min(maxH, m.actualBoundingBoxAscent * 2.5);
ctx.beginPath();
roundedRect(
ctx,
rect.x + padX / 2,
rect.y + (rect.height - h) / 2 + 1,
m.width + padX * 3,
h - 1,
theme.roundingRadius ?? 4
);
ctx.globalAlpha = hoverAmount;
ctx.fillStyle = withAlpha(theme.textDark, 0.1);
ctx.fill();

// restore
ctx.globalAlpha = 1;
ctx.fillStyle = theme.textDark;
ctx.textBaseline = "middle";

overrideCursor?.("text");
drawEditHoverIndicator(ctx, theme, hoverEffectTheme, displayData, rect, hoverAmount, overrideCursor);
}
drawTextCell(a, displayData, contentAlign, allowWrapping, hyperWrapping);
},
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/data-editor/stories/utils.tsx
Expand Up @@ -618,6 +618,15 @@ function getColumnsForCellTypes(): GridColumnWithMockingInfo[] {
data: name,
displayData: name,
allowOverlay: true,
hoverEffect: true,
themeOverride: {
cellVerticalPadding: 8,
cellHorizontalPadding: 8,
},
hoverEffectTheme: {
bgColor: "#f4f4f4",
fullSize: true,
},
};
},
},
Expand All @@ -633,6 +642,15 @@ function getColumnsForCellTypes(): GridColumnWithMockingInfo[] {
data: age,
displayData: `${age}`,
allowOverlay: true,
hoverEffect: true,
themeOverride: {
cellVerticalPadding: 8,
cellHorizontalPadding: 8,
},
hoverEffectTheme: {
bgColor: "#f4f4f4",
fullSize: true,
},
};
},
},
Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/docs/examples/all-cell-kinds.stories.tsx
Expand Up @@ -39,7 +39,7 @@ export const AllCellKinds: React.VFC = () => {
columns={cols}
onCellEdited={setCellValue}
onPaste={true}
// rowHeight={55}
rowHeight={44}
onColumnResize={onColumnResize}
highlightRegions={[
{
Expand All @@ -52,6 +52,9 @@ export const AllCellKinds: React.VFC = () => {
},
},
]}
cellActivationBehavior="single-click"
editorBloom={[-4, -4]}
drawFocusRing={false}
rows={1000}
/>
);
Expand Down
8 changes: 8 additions & 0 deletions packages/core/src/internal/data-grid/data-grid-types.ts
Expand Up @@ -330,6 +330,11 @@ export interface ProtectedCell extends BaseGridCell {
readonly kind: GridCellKind.Protected;
}

export interface HoverEffectTheme {
bgColor: string;
fullSize: boolean;
}

/** @category Cells */
export interface TextCell extends BaseGridCell {
readonly kind: GridCellKind.Text;
Expand All @@ -338,6 +343,7 @@ export interface TextCell extends BaseGridCell {
readonly readonly?: boolean;
readonly allowWrapping?: boolean;
readonly hoverEffect?: boolean;
readonly hoverEffectTheme?: HoverEffectTheme;
}

/** @category Cells */
Expand All @@ -350,6 +356,8 @@ export interface NumberCell extends BaseGridCell {
readonly allowNegative?: boolean;
readonly thousandSeparator?: boolean | string;
readonly decimalSeparator?: string;
readonly hoverEffect?: boolean;
readonly hoverEffectTheme?: HoverEffectTheme;
}

/** @category Cells */
Expand Down
@@ -0,0 +1,61 @@
import type { FullTheme } from "../../../common/styles.js";
import type { Rectangle, HoverEffectTheme } from "../../../index.js";
import { roundedRect, measureTextCached } from "./data-grid-lib.js";
import { withAlpha } from "../color-parser.js";

export function drawEditHoverIndicator(
ctx: CanvasRenderingContext2D,
theme: FullTheme,
effectTheme: HoverEffectTheme | undefined,
displayData: string,
rect: Rectangle,
hoverAmount: number,
overrideCursor: ((cursor: React.CSSProperties["cursor"] | undefined) => void) | undefined
) {
ctx.textBaseline = "alphabetic";

const effectRect = getHoverEffectRect(ctx, rect, displayData, theme, effectTheme?.fullSize ?? false);

ctx.beginPath();
roundedRect(ctx, effectRect.x, effectRect.y, effectRect.width, effectRect.height, theme.roundingRadius ?? 4);
ctx.globalAlpha = hoverAmount;
ctx.fillStyle = effectTheme?.bgColor ?? withAlpha(theme.textDark, 0.1);
ctx.fill();

// restore
ctx.globalAlpha = 1;
ctx.fillStyle = theme.textDark;
ctx.textBaseline = "middle";

overrideCursor?.("text");
}

function getHoverEffectRect(
ctx: CanvasRenderingContext2D,
cellRect: Rectangle,
displayData: string,
theme: FullTheme,
fullSize: boolean
): Rectangle {
const padX = theme.cellHorizontalPadding;
const padY = theme.cellVerticalPadding;

if (fullSize) {
return {
x: cellRect.x + padX / 2,
y: cellRect.y + padY / 2 + 1,
width: cellRect.width - padX,
height: cellRect.height - padY - 1,
};
}

const m = measureTextCached(displayData, ctx, theme.baseFontFull, "alphabetic");
const maxH = cellRect.height - padY;
const h = Math.min(maxH, m.actualBoundingBoxAscent * 2.5);
return {
x: cellRect.x + padX / 2,
y: cellRect.y + (cellRect.height - h) / 2 + 1,
width: m.width + padX * 3,
height: h - 1,
};
}