argent-grid 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +69 -0
- package/.github/workflows/pages.yml +6 -12
- package/.storybook/main.ts +20 -0
- package/.storybook/preview.ts +18 -0
- package/.storybook/tsconfig.json +24 -0
- package/AGENTS.md +2 -2
- package/README.md +51 -34
- package/angular.json +66 -0
- package/biome.json +66 -0
- package/demo-app/e2e/selection-screenshot.spec.ts +20 -0
- package/docs/AG-GRID-COMPARISON.md +725 -0
- package/docs/CELL-RENDERER-GUIDE.md +241 -0
- package/docs/CONTEXT-MENU-GUIDE.md +371 -0
- package/docs/LIVE-DATA-OPTIMIZATIONS.md +497 -0
- package/docs/PERFORMANCE-OPTIMIZATIONS-PHASE1.md +162 -0
- package/docs/PERFORMANCE-REVIEW.md +571 -0
- package/docs/RESEARCH-STATUS.md +234 -0
- package/docs/STATE-PERSISTENCE-GUIDE.md +370 -0
- package/docs/STORYBOOK-REFACTOR.md +215 -0
- package/docs/STORYBOOK-STATUS.md +156 -0
- package/docs/TEST-COVERAGE-REPORT.md +276 -0
- package/docs/THEME-API-GUIDE.md +445 -0
- package/docs/THEME-API-PLAN.md +364 -0
- package/e2e/advanced.spec.ts +109 -0
- package/e2e/argentgrid.spec.ts +65 -0
- package/e2e/benchmark.spec.ts +52 -0
- package/e2e/screenshots.spec.ts +52 -0
- package/e2e/theming.spec.ts +35 -0
- package/e2e/visual.spec.ts +91 -0
- package/e2e/visual.spec.ts-snapshots/grid-default.png +0 -0
- package/e2e/visual.spec.ts-snapshots/grid-empty-state.png +0 -0
- package/e2e/visual.spec.ts-snapshots/grid-filter-popup.png +0 -0
- package/e2e/visual.spec.ts-snapshots/grid-scroll-borders.png +0 -0
- package/e2e/visual.spec.ts-snapshots/grid-sidebar-buttons.png +0 -0
- package/e2e/visual.spec.ts-snapshots/grid-text-filter.png +0 -0
- package/e2e/visual.spec.ts-snapshots/grid-with-selection.png +0 -0
- package/package.json +20 -6
- package/plan.md +50 -18
- package/playwright.config.ts +38 -0
- package/setup-vitest.ts +10 -13
- package/src/lib/argent-grid.module.ts +10 -12
- package/src/lib/components/argent-grid.component.css +327 -76
- package/src/lib/components/argent-grid.component.html +186 -64
- package/src/lib/components/argent-grid.component.spec.ts +120 -160
- package/src/lib/components/argent-grid.component.ts +642 -189
- package/src/lib/components/argent-grid.selection.spec.ts +132 -0
- package/src/lib/components/set-filter/set-filter.component.ts +302 -0
- package/src/lib/directives/ag-grid-compatibility.directive.ts +16 -26
- package/src/lib/directives/click-outside.directive.ts +19 -0
- package/src/lib/rendering/canvas-renderer.spec.ts +366 -0
- package/src/lib/rendering/canvas-renderer.ts +418 -305
- package/src/lib/rendering/live-data-handler.ts +110 -0
- package/src/lib/rendering/live-data-optimizations.ts +133 -0
- package/src/lib/rendering/render/blit.spec.ts +16 -27
- package/src/lib/rendering/render/blit.ts +48 -36
- package/src/lib/rendering/render/cells.spec.ts +132 -0
- package/src/lib/rendering/render/cells.ts +46 -24
- package/src/lib/rendering/render/column-utils.ts +73 -0
- package/src/lib/rendering/render/hit-test.ts +55 -0
- package/src/lib/rendering/render/index.ts +79 -76
- package/src/lib/rendering/render/lines.ts +43 -43
- package/src/lib/rendering/render/primitives.ts +161 -0
- package/src/lib/rendering/render/theme.spec.ts +8 -12
- package/src/lib/rendering/render/theme.ts +7 -10
- package/src/lib/rendering/render/types.ts +2 -2
- package/src/lib/rendering/render/walk.spec.ts +35 -38
- package/src/lib/rendering/render/walk.ts +60 -50
- package/src/lib/rendering/utils/damage-tracker.spec.ts +8 -7
- package/src/lib/rendering/utils/damage-tracker.ts +6 -18
- package/src/lib/rendering/utils/index.ts +1 -1
- package/src/lib/services/grid.service.set-filter.spec.ts +219 -0
- package/src/lib/services/grid.service.spec.ts +1165 -201
- package/src/lib/services/grid.service.ts +819 -187
- package/src/lib/themes/parts/color-schemes.ts +132 -0
- package/src/lib/themes/parts/icon-sets.ts +258 -0
- package/src/lib/themes/theme-builder.ts +347 -0
- package/src/lib/themes/theme-quartz.ts +72 -0
- package/src/lib/themes/types.ts +238 -0
- package/src/lib/types/ag-grid-types.ts +73 -14
- package/src/public-api.ts +39 -9
- package/src/stories/Advanced.stories.ts +188 -0
- package/src/stories/ArgentGrid.stories.ts +277 -0
- package/src/stories/Benchmark.stories.ts +74 -0
- package/src/stories/CellRenderers.stories.ts +221 -0
- package/src/stories/Filtering.stories.ts +252 -0
- package/src/stories/Grouping.stories.ts +217 -0
- package/src/stories/Theming.stories.ts +124 -0
- package/src/stories/benchmark-wrapper.component.ts +315 -0
- package/tsconfig.storybook.json +10 -0
- package/vitest.config.ts +9 -9
- package/demo-app/README.md +0 -70
- package/demo-app/angular.json +0 -78
- package/demo-app/e2e/benchmark.spec.ts +0 -53
- package/demo-app/e2e/demo-page.spec.ts +0 -77
- package/demo-app/e2e/grid-features.spec.ts +0 -269
- package/demo-app/package-lock.json +0 -14023
- package/demo-app/package.json +0 -36
- package/demo-app/playwright-test-menu.js +0 -19
- package/demo-app/playwright.config.ts +0 -23
- package/demo-app/src/app/app.component.ts +0 -10
- package/demo-app/src/app/app.config.ts +0 -13
- package/demo-app/src/app/app.routes.ts +0 -7
- package/demo-app/src/app/demo-page/demo-page.component.css +0 -313
- package/demo-app/src/app/demo-page/demo-page.component.html +0 -124
- package/demo-app/src/app/demo-page/demo-page.component.ts +0 -366
- package/demo-app/src/index.html +0 -19
- package/demo-app/src/main.ts +0 -6
- package/demo-app/tsconfig.json +0 -31
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* Handles drawing of individual cells with prep/draw cycle optimization.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import { CellDrawContext, ColumnPrepResult, GridTheme } from './types';
|
|
7
|
+
import { ColDef, Column, GridApi, IRowNode } from '../../types/ag-grid-types';
|
|
9
8
|
import { getFontFromTheme } from './theme';
|
|
9
|
+
import { CellDrawContext, ColumnPrepResult, GridTheme } from './types';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Get value from object using path (e.g. 'pivotData.NY.salary')
|
|
@@ -14,8 +14,8 @@ import { getFontFromTheme } from './theme';
|
|
|
14
14
|
export function getValueByPath(obj: any, path: string): any {
|
|
15
15
|
if (!path || !obj) return undefined;
|
|
16
16
|
if (!path.includes('.')) return obj[path];
|
|
17
|
-
|
|
18
|
-
return path.split('.').reduce((acc, part) => acc
|
|
17
|
+
|
|
18
|
+
return path.split('.').reduce((acc, part) => acc?.[part], obj);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
// ============================================================================
|
|
@@ -75,7 +75,7 @@ export function drawCell<TData = any>(
|
|
|
75
75
|
prep: ColumnPrepResult<TData>,
|
|
76
76
|
context: CellDrawContext<TData>
|
|
77
77
|
): void {
|
|
78
|
-
const {
|
|
78
|
+
const { rowNode } = context;
|
|
79
79
|
|
|
80
80
|
// Draw cell background
|
|
81
81
|
drawCellBackground(ctx, context);
|
|
@@ -113,7 +113,7 @@ export function drawCellBackground<TData = any>(
|
|
|
113
113
|
*/
|
|
114
114
|
export function drawCellContent<TData = any>(
|
|
115
115
|
ctx: CanvasRenderingContext2D,
|
|
116
|
-
|
|
116
|
+
_prep: ColumnPrepResult<TData>,
|
|
117
117
|
context: CellDrawContext<TData>
|
|
118
118
|
): void {
|
|
119
119
|
const { x, y, width, height, formattedValue, theme } = context;
|
|
@@ -142,10 +142,10 @@ export function drawCellContent<TData = any>(
|
|
|
142
142
|
*/
|
|
143
143
|
export function drawGroupIndicators<TData = any>(
|
|
144
144
|
ctx: CanvasRenderingContext2D,
|
|
145
|
-
|
|
145
|
+
_prep: ColumnPrepResult<TData>,
|
|
146
146
|
context: CellDrawContext<TData>
|
|
147
147
|
): void {
|
|
148
|
-
const { x, y,
|
|
148
|
+
const { x, y, height, column, rowNode, theme } = context;
|
|
149
149
|
|
|
150
150
|
if (!rowNode) return;
|
|
151
151
|
|
|
@@ -174,7 +174,7 @@ export function drawGroupIndicators<TData = any>(
|
|
|
174
174
|
const size = theme.groupIndicatorSize;
|
|
175
175
|
const centerX = Math.floor(indicatorX + size / 2);
|
|
176
176
|
const centerY = Math.floor(indicatorY);
|
|
177
|
-
|
|
177
|
+
|
|
178
178
|
// Horizontal line
|
|
179
179
|
ctx.moveTo(Math.floor(indicatorX), centerY);
|
|
180
180
|
ctx.lineTo(Math.floor(indicatorX + size), centerY);
|
|
@@ -212,7 +212,7 @@ export function truncateText(
|
|
|
212
212
|
|
|
213
213
|
while (start < end) {
|
|
214
214
|
const mid = Math.floor((start + end) / 2);
|
|
215
|
-
const truncated = text.slice(0, mid)
|
|
215
|
+
const truncated = `${text.slice(0, mid)}...`;
|
|
216
216
|
|
|
217
217
|
if (ctx.measureText(truncated).width <= maxWidth) {
|
|
218
218
|
start = mid + 1;
|
|
@@ -221,16 +221,13 @@ export function truncateText(
|
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
-
return text.slice(0, Math.max(0, start - 1))
|
|
224
|
+
return `${text.slice(0, Math.max(0, start - 1))}...`;
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
/**
|
|
228
228
|
* Measure text width
|
|
229
229
|
*/
|
|
230
|
-
export function measureText(
|
|
231
|
-
ctx: CanvasRenderingContext2D,
|
|
232
|
-
text: string
|
|
233
|
-
): number {
|
|
230
|
+
export function measureText(ctx: CanvasRenderingContext2D, text: string): number {
|
|
234
231
|
return ctx.measureText(text).width;
|
|
235
232
|
}
|
|
236
233
|
|
|
@@ -240,7 +237,7 @@ export function measureText(
|
|
|
240
237
|
export function calculateColumnWidth<TData = any>(
|
|
241
238
|
ctx: CanvasRenderingContext2D,
|
|
242
239
|
column: Column,
|
|
243
|
-
|
|
240
|
+
_colDef: ColDef<TData> | null,
|
|
244
241
|
theme: GridTheme,
|
|
245
242
|
sampleData: any[],
|
|
246
243
|
maxRows: number = 100
|
|
@@ -278,6 +275,16 @@ export function calculateColumnWidth<TData = any>(
|
|
|
278
275
|
/**
|
|
279
276
|
* Get formatted cell value
|
|
280
277
|
*/
|
|
278
|
+
/**
|
|
279
|
+
* Strip HTML tags from string
|
|
280
|
+
* Supports basic cellRenderer that returns HTML strings
|
|
281
|
+
* Note: Only plain text is rendered - colors, backgrounds, etc. are NOT supported
|
|
282
|
+
*/
|
|
283
|
+
export function stripHtmlTags(html: string): string {
|
|
284
|
+
if (!html) return '';
|
|
285
|
+
return html.replace(/<[^>]*>/g, '');
|
|
286
|
+
}
|
|
287
|
+
|
|
281
288
|
export function getFormattedValue<TData = any>(
|
|
282
289
|
value: any,
|
|
283
290
|
colDef: ColDef<TData> | null,
|
|
@@ -289,6 +296,27 @@ export function getFormattedValue<TData = any>(
|
|
|
289
296
|
return '';
|
|
290
297
|
}
|
|
291
298
|
|
|
299
|
+
// Use custom cellRenderer if provided
|
|
300
|
+
if (colDef && typeof colDef.cellRenderer === 'function') {
|
|
301
|
+
try {
|
|
302
|
+
const result = colDef.cellRenderer({
|
|
303
|
+
value,
|
|
304
|
+
data,
|
|
305
|
+
node: rowNode,
|
|
306
|
+
colDef,
|
|
307
|
+
api,
|
|
308
|
+
});
|
|
309
|
+
// Handle both string and Promise<string> returns
|
|
310
|
+
if (typeof result === 'string') {
|
|
311
|
+
return stripHtmlTags(result);
|
|
312
|
+
}
|
|
313
|
+
// For async renderers, return value as string (will be updated on next render)
|
|
314
|
+
return String(value);
|
|
315
|
+
} catch (e) {
|
|
316
|
+
console.warn('Cell renderer error:', e);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
292
320
|
// Use custom formatter if provided
|
|
293
321
|
if (colDef && typeof colDef.valueFormatter === 'function') {
|
|
294
322
|
try {
|
|
@@ -338,13 +366,7 @@ export function renderRow<TData = any>(
|
|
|
338
366
|
|
|
339
367
|
const x = getCellX(column);
|
|
340
368
|
const value = column.field ? getValueByPath(rowNode.data, column.field) : undefined;
|
|
341
|
-
const formattedValue = getFormattedValue(
|
|
342
|
-
value,
|
|
343
|
-
prep.colDef,
|
|
344
|
-
rowNode.data,
|
|
345
|
-
rowNode,
|
|
346
|
-
api
|
|
347
|
-
);
|
|
369
|
+
const formattedValue = getFormattedValue(value, prep.colDef, rowNode.data, rowNode, api);
|
|
348
370
|
|
|
349
371
|
const context: CellDrawContext<TData> = {
|
|
350
372
|
ctx,
|
|
@@ -366,4 +388,4 @@ export function renderRow<TData = any>(
|
|
|
366
388
|
|
|
367
389
|
drawCell(ctx, prep, context);
|
|
368
390
|
}
|
|
369
|
-
}
|
|
391
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Column Utilities for Canvas Renderer
|
|
3
|
+
*
|
|
4
|
+
* Helper functions for column management and definition lookup.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ColDef, Column, GridApi } from '../../types/ag-grid-types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Find the Column Definition for a given Column
|
|
11
|
+
*/
|
|
12
|
+
export function getColumnDef<TData = any>(
|
|
13
|
+
column: Column,
|
|
14
|
+
gridApi: GridApi<TData>
|
|
15
|
+
): ColDef<TData> | null {
|
|
16
|
+
const allDefs = gridApi.getColumnDefs();
|
|
17
|
+
if (!allDefs) return null;
|
|
18
|
+
|
|
19
|
+
const targetId = column.colId;
|
|
20
|
+
const targetField = column.field?.toString();
|
|
21
|
+
|
|
22
|
+
for (const def of allDefs) {
|
|
23
|
+
if ('children' in def) {
|
|
24
|
+
const found = def.children.find((c) => {
|
|
25
|
+
const cDef = c as ColDef;
|
|
26
|
+
return (
|
|
27
|
+
cDef.colId === targetId ||
|
|
28
|
+
cDef.field?.toString() === targetId ||
|
|
29
|
+
(targetField && cDef.field?.toString() === targetField)
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
if (found) return found as ColDef<TData>;
|
|
33
|
+
} else {
|
|
34
|
+
const cDef = def as ColDef;
|
|
35
|
+
if (
|
|
36
|
+
cDef.colId === targetId ||
|
|
37
|
+
cDef.field?.toString() === targetId ||
|
|
38
|
+
(targetField && cDef.field?.toString() === targetField)
|
|
39
|
+
) {
|
|
40
|
+
return def as ColDef<TData>;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Get X position for a column
|
|
49
|
+
*/
|
|
50
|
+
export function getColumnX(
|
|
51
|
+
targetCol: Column,
|
|
52
|
+
columnPositions: Map<string, number>,
|
|
53
|
+
scrollLeft: number,
|
|
54
|
+
leftPinnedWidth: number,
|
|
55
|
+
rightPinnedWidth: number,
|
|
56
|
+
viewportWidth: number
|
|
57
|
+
): number {
|
|
58
|
+
// Use cached column position (O(1) lookup)
|
|
59
|
+
const baseX = columnPositions.get(targetCol.colId) || 0;
|
|
60
|
+
|
|
61
|
+
// Adjust for pinned columns and scroll position
|
|
62
|
+
if (targetCol.pinned === 'left') {
|
|
63
|
+
return baseX;
|
|
64
|
+
} else if (targetCol.pinned === 'right') {
|
|
65
|
+
// When right-pinned, we need to know the offset from the right edge
|
|
66
|
+
// Our positions are accumulated from left to right.
|
|
67
|
+
// We need to find where the right-pinned section starts.
|
|
68
|
+
const rightPinnedStartX = viewportWidth - rightPinnedWidth;
|
|
69
|
+
return rightPinnedStartX + (baseX - (viewportWidth - rightPinnedWidth));
|
|
70
|
+
} else {
|
|
71
|
+
return leftPinnedWidth - scrollLeft + (baseX - leftPinnedWidth);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hit Testing for Canvas Renderer
|
|
3
|
+
*
|
|
4
|
+
* Utilities for detecting which grid element is under a given coordinate.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Column } from '../../types/ag-grid-types';
|
|
8
|
+
import { getColumnAtX, getRowAtY } from './walk';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Result of a grid hit test
|
|
12
|
+
*/
|
|
13
|
+
export interface HitTestResult {
|
|
14
|
+
rowIndex: number;
|
|
15
|
+
columnIndex: number;
|
|
16
|
+
column: Column | null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Perform a hit test on the grid
|
|
21
|
+
*/
|
|
22
|
+
export function performHitTest(
|
|
23
|
+
canvasX: number,
|
|
24
|
+
canvasY: number,
|
|
25
|
+
rowHeight: number,
|
|
26
|
+
scrollTop: number,
|
|
27
|
+
scrollLeft: number,
|
|
28
|
+
viewportWidth: number,
|
|
29
|
+
columns: Column[]
|
|
30
|
+
): HitTestResult {
|
|
31
|
+
// Use walker utility for row detection
|
|
32
|
+
const rowIndex = getRowAtY(canvasY, rowHeight, scrollTop);
|
|
33
|
+
|
|
34
|
+
// Use walker utility for column detection
|
|
35
|
+
const result = getColumnAtX(columns, canvasX, scrollLeft, viewportWidth);
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
rowIndex,
|
|
39
|
+
columnIndex: result.index,
|
|
40
|
+
column: result.column,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get the horizontal offset of a center column
|
|
46
|
+
*/
|
|
47
|
+
export function getCenterColumnOffset(targetCol: Column, columns: Column[]): number {
|
|
48
|
+
const centerColumns = columns.filter((c) => !c.pinned);
|
|
49
|
+
let offset = 0;
|
|
50
|
+
for (const col of centerColumns) {
|
|
51
|
+
if (col === targetCol) return offset;
|
|
52
|
+
offset += col.width;
|
|
53
|
+
}
|
|
54
|
+
return offset;
|
|
55
|
+
}
|
|
@@ -4,102 +4,105 @@
|
|
|
4
4
|
* Exports all rendering-related modules.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
//
|
|
8
|
-
export {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
RowWalkCallback,
|
|
16
|
-
CellWalkCallback,
|
|
17
|
-
CellDrawContext,
|
|
18
|
-
ColumnPrepResult,
|
|
19
|
-
BlitResult,
|
|
20
|
-
BufferPair,
|
|
21
|
-
DamageType,
|
|
22
|
-
DirtyRegions,
|
|
23
|
-
GridTheme,
|
|
24
|
-
PartialTheme,
|
|
25
|
-
RenderState,
|
|
26
|
-
VisibleRange,
|
|
27
|
-
HitTestResult,
|
|
28
|
-
GridMouseEvent,
|
|
29
|
-
} from './types';
|
|
30
|
-
|
|
31
|
-
// Theme (re-export the DEFAULT_THEME and utilities)
|
|
32
|
-
export {
|
|
33
|
-
DEFAULT_THEME,
|
|
34
|
-
DARK_THEME,
|
|
35
|
-
THEME_PRESETS,
|
|
36
|
-
mergeTheme,
|
|
37
|
-
getFontFromTheme,
|
|
38
|
-
getRowTheme,
|
|
39
|
-
getCellBackgroundColor,
|
|
40
|
-
getThemePreset,
|
|
41
|
-
createTheme,
|
|
42
|
-
} from './theme';
|
|
43
|
-
|
|
44
|
-
// Walker functions
|
|
45
|
-
export {
|
|
46
|
-
walkColumns,
|
|
47
|
-
getPositionedColumns,
|
|
48
|
-
getPinnedWidths,
|
|
49
|
-
walkRows,
|
|
50
|
-
getVisibleRowRange,
|
|
51
|
-
getRowY,
|
|
52
|
-
walkCells,
|
|
53
|
-
getColumnAtX,
|
|
54
|
-
getColumnIndex,
|
|
55
|
-
getTotalColumnWidth,
|
|
56
|
-
getRowAtY,
|
|
57
|
-
isRowVisible,
|
|
58
|
-
calculateVisibleRange,
|
|
59
|
-
} from './walk';
|
|
60
|
-
|
|
7
|
+
// Live data optimizations
|
|
8
|
+
export { LiveDataOptimizations } from '../live-data-optimizations';
|
|
9
|
+
// Rendering primitives
|
|
10
|
+
export { drawCheckbox, drawGroupIndicator, drawSparkline } from './primitives';
|
|
11
|
+
// Hit testing
|
|
12
|
+
export * from './hit-test';
|
|
13
|
+
// Column utilities
|
|
14
|
+
export * from './column-utils';
|
|
61
15
|
// Blitting optimization
|
|
62
16
|
export {
|
|
63
|
-
|
|
64
|
-
MAX_BLIT_DELTA_RATIO,
|
|
65
|
-
shouldBlit,
|
|
66
|
-
calculateBlit,
|
|
17
|
+
BlitState,
|
|
67
18
|
blitLastFrame,
|
|
19
|
+
calculateBlit,
|
|
68
20
|
createBufferPair,
|
|
69
|
-
swapBuffers,
|
|
70
21
|
displayBuffer,
|
|
22
|
+
MAX_BLIT_DELTA_RATIO,
|
|
23
|
+
MIN_BLIT_DELTA,
|
|
71
24
|
resizeBufferPair,
|
|
72
|
-
|
|
25
|
+
shouldBlit,
|
|
26
|
+
swapBuffers,
|
|
73
27
|
} from './blit';
|
|
74
|
-
|
|
75
28
|
// Cell rendering (explicit exports to avoid conflicts)
|
|
76
29
|
export {
|
|
77
|
-
|
|
78
|
-
prepColumns,
|
|
30
|
+
calculateColumnWidth,
|
|
79
31
|
drawCell,
|
|
80
32
|
drawCellBackground,
|
|
81
33
|
drawCellContent,
|
|
82
34
|
drawGroupIndicators,
|
|
83
|
-
truncateText,
|
|
84
|
-
measureText,
|
|
85
|
-
calculateColumnWidth,
|
|
86
35
|
getFormattedValue,
|
|
87
36
|
getValueByPath,
|
|
37
|
+
measureText,
|
|
38
|
+
prepColumn,
|
|
39
|
+
prepColumns,
|
|
88
40
|
renderRow,
|
|
41
|
+
truncateText,
|
|
89
42
|
} from './cells';
|
|
90
|
-
|
|
91
43
|
// Grid lines
|
|
92
44
|
export {
|
|
93
|
-
drawCrispLine,
|
|
94
|
-
drawHorizontalLine,
|
|
95
|
-
drawVerticalLine,
|
|
96
|
-
drawRowLines,
|
|
97
|
-
drawColumnLines,
|
|
98
|
-
getColumnBorderPositions,
|
|
99
|
-
drawGridLines,
|
|
100
45
|
drawBorder,
|
|
101
46
|
drawCellSelectionBorder,
|
|
102
|
-
|
|
47
|
+
drawColumnLines,
|
|
48
|
+
drawCrispLine,
|
|
49
|
+
drawGridLines,
|
|
50
|
+
drawHorizontalLine,
|
|
103
51
|
drawPinnedRegionBorders,
|
|
104
52
|
drawPinnedRegionShadows,
|
|
105
|
-
|
|
53
|
+
drawRangeSelectionBorder,
|
|
54
|
+
drawRowLines,
|
|
55
|
+
drawVerticalLine,
|
|
56
|
+
getColumnBorderPositions,
|
|
57
|
+
} from './lines';
|
|
58
|
+
// Theme (re-export the DEFAULT_THEME and utilities)
|
|
59
|
+
export {
|
|
60
|
+
createTheme,
|
|
61
|
+
DARK_THEME,
|
|
62
|
+
DEFAULT_THEME,
|
|
63
|
+
getCellBackgroundColor,
|
|
64
|
+
getFontFromTheme,
|
|
65
|
+
getRowTheme,
|
|
66
|
+
getThemePreset,
|
|
67
|
+
mergeTheme,
|
|
68
|
+
THEME_PRESETS,
|
|
69
|
+
} from './theme';
|
|
70
|
+
// Types (base definitions)
|
|
71
|
+
export {
|
|
72
|
+
BlitResult,
|
|
73
|
+
BufferPair,
|
|
74
|
+
CellDrawContext,
|
|
75
|
+
CellWalkCallback,
|
|
76
|
+
ColumnPrepResult,
|
|
77
|
+
ColumnWalkCallback,
|
|
78
|
+
DamageType,
|
|
79
|
+
DirtyRegions,
|
|
80
|
+
GridMouseEvent,
|
|
81
|
+
GridTheme,
|
|
82
|
+
HitTestResult,
|
|
83
|
+
PartialTheme,
|
|
84
|
+
Point,
|
|
85
|
+
PositionedColumn,
|
|
86
|
+
Rectangle,
|
|
87
|
+
RenderState,
|
|
88
|
+
RowWalkCallback,
|
|
89
|
+
ScrollPosition,
|
|
90
|
+
Size,
|
|
91
|
+
VisibleRange,
|
|
92
|
+
} from './types';
|
|
93
|
+
// Walker functions
|
|
94
|
+
export {
|
|
95
|
+
calculateVisibleRange,
|
|
96
|
+
getColumnAtX,
|
|
97
|
+
getColumnIndex,
|
|
98
|
+
getPinnedWidths,
|
|
99
|
+
getPositionedColumns,
|
|
100
|
+
getRowAtY,
|
|
101
|
+
getRowY,
|
|
102
|
+
getTotalColumnWidth,
|
|
103
|
+
getVisibleRowRange,
|
|
104
|
+
isRowVisible,
|
|
105
|
+
walkCells,
|
|
106
|
+
walkColumns,
|
|
107
|
+
walkRows,
|
|
108
|
+
} from './walk';
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Draws grid lines (borders) efficiently.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { Column,
|
|
7
|
+
import { Column, GridApi } from '../../types/ag-grid-types';
|
|
8
8
|
import { GridTheme, Rectangle } from './types';
|
|
9
9
|
|
|
10
10
|
// ============================================================================
|
|
@@ -22,9 +22,14 @@ export function drawCrispLine(
|
|
|
22
22
|
y2: number
|
|
23
23
|
): void {
|
|
24
24
|
ctx.beginPath();
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
// For 1px lines, we want the center of the line to be at X.5
|
|
26
|
+
const snapX1 = Math.floor(x1) + 0.5;
|
|
27
|
+
const snapY1 = Math.floor(y1) + 0.5;
|
|
28
|
+
const snapX2 = Math.floor(x2) + 0.5;
|
|
29
|
+
const snapY2 = Math.floor(y2) + 0.5;
|
|
30
|
+
|
|
31
|
+
ctx.moveTo(snapX1, snapY1);
|
|
32
|
+
ctx.lineTo(snapX2, snapY2);
|
|
28
33
|
ctx.stroke();
|
|
29
34
|
}
|
|
30
35
|
|
|
@@ -66,7 +71,8 @@ export function drawRowLines(
|
|
|
66
71
|
rowHeight: number,
|
|
67
72
|
scrollTop: number,
|
|
68
73
|
viewportWidth: number,
|
|
69
|
-
theme: GridTheme
|
|
74
|
+
theme: GridTheme,
|
|
75
|
+
api?: GridApi
|
|
70
76
|
): void {
|
|
71
77
|
ctx.strokeStyle = theme.borderColor || theme.gridLineColor;
|
|
72
78
|
ctx.lineWidth = 1;
|
|
@@ -74,9 +80,12 @@ export function drawRowLines(
|
|
|
74
80
|
ctx.beginPath();
|
|
75
81
|
|
|
76
82
|
for (let row = startRow; row <= endRow; row++) {
|
|
77
|
-
const y = Math.floor(row * rowHeight - scrollTop)
|
|
78
|
-
|
|
79
|
-
|
|
83
|
+
const y = Math.floor(api ? api.getRowY(row) - scrollTop : row * rowHeight - scrollTop);
|
|
84
|
+
// Draw border at the bottom of the row (y-0.5) to match DOM border-bottom
|
|
85
|
+
const borderY = y - 0.5;
|
|
86
|
+
if (borderY < 0) continue; // Skip top border if it's outside
|
|
87
|
+
ctx.moveTo(0, borderY);
|
|
88
|
+
ctx.lineTo(viewportWidth, borderY);
|
|
80
89
|
}
|
|
81
90
|
|
|
82
91
|
ctx.stroke();
|
|
@@ -97,7 +106,8 @@ export function drawColumnLines(
|
|
|
97
106
|
theme: GridTheme,
|
|
98
107
|
startRow: number = 0,
|
|
99
108
|
endRow: number = 0,
|
|
100
|
-
rowHeight: number = 32
|
|
109
|
+
rowHeight: number = 32,
|
|
110
|
+
api?: GridApi
|
|
101
111
|
): void {
|
|
102
112
|
ctx.strokeStyle = theme.borderColor || theme.gridLineColor;
|
|
103
113
|
ctx.lineWidth = 1;
|
|
@@ -111,13 +121,15 @@ export function drawColumnLines(
|
|
|
111
121
|
);
|
|
112
122
|
|
|
113
123
|
// Calculate Y range for drawing
|
|
114
|
-
const drawY1 = Math.
|
|
115
|
-
|
|
124
|
+
const drawY1 = Math.floor(
|
|
125
|
+
api ? api.getRowY(startRow) - scrollTop : startRow * rowHeight - scrollTop
|
|
126
|
+
);
|
|
127
|
+
const drawY2 = Math.floor(api ? api.getRowY(endRow) - scrollTop : endRow * rowHeight - scrollTop);
|
|
116
128
|
|
|
117
129
|
ctx.beginPath();
|
|
118
130
|
|
|
119
131
|
for (const x of columnPositions) {
|
|
120
|
-
const borderX = Math.floor(x)
|
|
132
|
+
const borderX = Math.floor(x) - 0.5;
|
|
121
133
|
ctx.moveTo(borderX, drawY1);
|
|
122
134
|
ctx.lineTo(borderX, drawY2);
|
|
123
135
|
}
|
|
@@ -137,21 +149,21 @@ export function getColumnBorderPositions(
|
|
|
137
149
|
): number[] {
|
|
138
150
|
const positions: number[] = [];
|
|
139
151
|
|
|
140
|
-
const leftPinned = columns.filter(c => c.pinned === 'left');
|
|
141
|
-
const rightPinned = columns.filter(c => c.pinned === 'right');
|
|
142
|
-
const centerColumns = columns.filter(c => !c.pinned);
|
|
152
|
+
const leftPinned = columns.filter((c) => c.pinned === 'left');
|
|
153
|
+
const rightPinned = columns.filter((c) => c.pinned === 'right');
|
|
154
|
+
const centerColumns = columns.filter((c) => !c.pinned);
|
|
143
155
|
|
|
144
156
|
// Left pinned column borders
|
|
145
157
|
let x = 0;
|
|
146
158
|
for (const col of leftPinned) {
|
|
147
|
-
x += col.width;
|
|
159
|
+
x += Math.floor(col.width);
|
|
148
160
|
positions.push(x);
|
|
149
161
|
}
|
|
150
162
|
|
|
151
163
|
// Center column borders
|
|
152
|
-
x = leftPinnedWidth - scrollX;
|
|
164
|
+
x = Math.floor(leftPinnedWidth) - scrollX;
|
|
153
165
|
for (const col of centerColumns) {
|
|
154
|
-
x += col.width;
|
|
166
|
+
x += Math.floor(col.width);
|
|
155
167
|
// Only include if visible
|
|
156
168
|
if (x > leftPinnedWidth && x < viewportWidth - rightPinnedWidth) {
|
|
157
169
|
positions.push(x);
|
|
@@ -159,9 +171,9 @@ export function getColumnBorderPositions(
|
|
|
159
171
|
}
|
|
160
172
|
|
|
161
173
|
// Right pinned column borders
|
|
162
|
-
x = viewportWidth - rightPinnedWidth;
|
|
174
|
+
x = Math.floor(viewportWidth - rightPinnedWidth);
|
|
163
175
|
for (const col of rightPinned) {
|
|
164
|
-
x += col.width;
|
|
176
|
+
x += Math.floor(col.width);
|
|
165
177
|
positions.push(x);
|
|
166
178
|
}
|
|
167
179
|
|
|
@@ -183,10 +195,11 @@ export function drawGridLines(
|
|
|
183
195
|
viewportHeight: number,
|
|
184
196
|
leftPinnedWidth: number,
|
|
185
197
|
rightPinnedWidth: number,
|
|
186
|
-
theme: GridTheme
|
|
198
|
+
theme: GridTheme,
|
|
199
|
+
api?: GridApi
|
|
187
200
|
): void {
|
|
188
201
|
// Draw horizontal lines
|
|
189
|
-
drawRowLines(ctx, startRow, endRow, rowHeight, scrollTop, viewportWidth, theme);
|
|
202
|
+
drawRowLines(ctx, startRow, endRow, rowHeight, scrollTop, viewportWidth, theme, api);
|
|
190
203
|
|
|
191
204
|
// Draw vertical lines
|
|
192
205
|
drawColumnLines(
|
|
@@ -201,7 +214,8 @@ export function drawGridLines(
|
|
|
201
214
|
theme,
|
|
202
215
|
startRow,
|
|
203
216
|
endRow,
|
|
204
|
-
rowHeight
|
|
217
|
+
rowHeight,
|
|
218
|
+
api
|
|
205
219
|
);
|
|
206
220
|
}
|
|
207
221
|
|
|
@@ -261,11 +275,7 @@ export function drawRangeSelectionBorder(
|
|
|
261
275
|
lineWidth?: number;
|
|
262
276
|
} = {}
|
|
263
277
|
): void {
|
|
264
|
-
const {
|
|
265
|
-
color = '#1976d2',
|
|
266
|
-
fillColor = 'rgba(25, 118, 210, 0.1)',
|
|
267
|
-
lineWidth = 1
|
|
268
|
-
} = options;
|
|
278
|
+
const { color = '#1976d2', fillColor = 'rgba(25, 118, 210, 0.1)', lineWidth = 1 } = options;
|
|
269
279
|
|
|
270
280
|
// Draw fill
|
|
271
281
|
if (fillColor) {
|
|
@@ -304,7 +314,7 @@ export function drawPinnedRegionBorders(
|
|
|
304
314
|
// Left pinned border
|
|
305
315
|
if (leftPinnedWidth > 0) {
|
|
306
316
|
ctx.beginPath();
|
|
307
|
-
const x = Math.floor(leftPinnedWidth)
|
|
317
|
+
const x = Math.floor(leftPinnedWidth) - 0.5;
|
|
308
318
|
ctx.moveTo(x, 0);
|
|
309
319
|
ctx.lineTo(x, viewportHeight);
|
|
310
320
|
ctx.stroke();
|
|
@@ -313,7 +323,7 @@ export function drawPinnedRegionBorders(
|
|
|
313
323
|
// Right pinned border
|
|
314
324
|
if (rightPinnedWidth > 0) {
|
|
315
325
|
ctx.beginPath();
|
|
316
|
-
const x = Math.floor(viewportWidth - rightPinnedWidth)
|
|
326
|
+
const x = Math.floor(viewportWidth - rightPinnedWidth) - 0.5;
|
|
317
327
|
ctx.moveTo(x, 0);
|
|
318
328
|
ctx.lineTo(x, viewportHeight);
|
|
319
329
|
ctx.stroke();
|
|
@@ -332,12 +342,7 @@ export function drawPinnedRegionShadows(
|
|
|
332
342
|
): void {
|
|
333
343
|
// Left shadow (on the right edge of left pinned)
|
|
334
344
|
if (leftPinnedWidth > 0) {
|
|
335
|
-
const gradient = ctx.createLinearGradient(
|
|
336
|
-
leftPinnedWidth,
|
|
337
|
-
0,
|
|
338
|
-
leftPinnedWidth + 4,
|
|
339
|
-
0
|
|
340
|
-
);
|
|
345
|
+
const gradient = ctx.createLinearGradient(leftPinnedWidth, 0, leftPinnedWidth + 4, 0);
|
|
341
346
|
gradient.addColorStop(0, 'rgba(0, 0, 0, 0.1)');
|
|
342
347
|
gradient.addColorStop(1, 'rgba(0, 0, 0, 0)');
|
|
343
348
|
|
|
@@ -348,16 +353,11 @@ export function drawPinnedRegionShadows(
|
|
|
348
353
|
// Right shadow (on the left edge of right pinned)
|
|
349
354
|
if (rightPinnedWidth > 0) {
|
|
350
355
|
const shadowX = viewportWidth - rightPinnedWidth;
|
|
351
|
-
const gradient = ctx.createLinearGradient(
|
|
352
|
-
shadowX - 4,
|
|
353
|
-
0,
|
|
354
|
-
shadowX,
|
|
355
|
-
0
|
|
356
|
-
);
|
|
356
|
+
const gradient = ctx.createLinearGradient(shadowX - 4, 0, shadowX, 0);
|
|
357
357
|
gradient.addColorStop(0, 'rgba(0, 0, 0, 0)');
|
|
358
358
|
gradient.addColorStop(1, 'rgba(0, 0, 0, 0.1)');
|
|
359
359
|
|
|
360
360
|
ctx.fillStyle = gradient;
|
|
361
361
|
ctx.fillRect(shadowX - 4, 0, 4, viewportHeight);
|
|
362
362
|
}
|
|
363
|
-
}
|
|
363
|
+
}
|