diff --git a/.changeset/fix-grid-copy-row-start.md b/.changeset/fix-grid-copy-row-start.md new file mode 100644 index 000000000..bd6bb01f6 --- /dev/null +++ b/.changeset/fix-grid-copy-row-start.md @@ -0,0 +1,5 @@ +--- +'@clickhouse/click-ui': patch +--- + +Copy selected Grid columns from the current row offset. diff --git a/src/components/Grid/Grid.test.tsx b/src/components/Grid/Grid.test.tsx index a6807acde..2706daaa0 100644 --- a/src/components/Grid/Grid.test.tsx +++ b/src/components/Grid/Grid.test.tsx @@ -3,6 +3,12 @@ import type { CellProps, GridProps } from '@/components/Grid/types'; import { renderCUI } from '@/utils/test-utils'; import { SelectionFocus } from './types'; import { ReactNode } from 'react'; +import { fireEvent } from '@testing-library/dom'; +import copyGridElements from './copyGridElements'; + +vi.mock('./copyGridElements', () => ({ + default: vi.fn().mockResolvedValue(undefined), +})); const Cell: CellProps = ({ type, rowIndex, columnIndex, isScrolling, ...props }) => { let content = `${rowIndex} ${columnIndex} - ${type}`; @@ -145,4 +151,23 @@ describe('Grid', () => { const computedHeight = window.getComputedStyle(cell).height; expect(computedHeight).toBe('100%'); }); + + it('passes rowStart to the default copy handler', () => { + vi.mocked(copyGridElements).mockClear(); + const { getByTestId } = renderGrid({ + rowStart: 100, + rowCount: 3, + columnCount: 2, + focus: { row: 100, column: 0 }, + }); + + fireEvent.keyDown(getByTestId('grid-outer-element'), { + key: 'c', + ctrlKey: true, + }); + + expect(copyGridElements).toHaveBeenCalledWith( + expect.objectContaining({ rowStart: 100, rowCount: 3, columnCount: 2 }) + ); + }); }); diff --git a/src/components/Grid/Grid.tsx b/src/components/Grid/Grid.tsx index 6cc8e98a6..ace19d792 100644 --- a/src/components/Grid/Grid.tsx +++ b/src/components/Grid/Grid.tsx @@ -158,6 +158,7 @@ export const Grid = forwardRef( focus: focusProp ?? focus, rowCount, columnCount, + rowStart, outerRef: outerRef, }); @@ -192,6 +193,7 @@ export const Grid = forwardRef( focus, focusProp, rowCount, + rowStart, selection, showToast, onCopyCallback, diff --git a/src/components/Grid/copyGridElements.test.tsx b/src/components/Grid/copyGridElements.test.tsx index fe2e56069..415fed8c2 100644 --- a/src/components/Grid/copyGridElements.test.tsx +++ b/src/components/Grid/copyGridElements.test.tsx @@ -66,4 +66,56 @@ describe('copyGridElements', () => { [10, 0], ]); }); + + it('copies selected columns using the current rowStart', async () => { + const outerRef = { current: document.createElement('div') }; + + await copyGridElements({ + cell: Cell, + selection: { + type: 'columns', + columns: new Set([2, 0]), + anchorColumn: 2, + }, + rowCount: 3, + columnCount: 4, + rowStart: 100, + focus: { row: 100, column: 0 }, + outerRef, + }); + + expect(renderedCells).toEqual([ + [100, 0], + [100, 2], + [101, 0], + [101, 2], + [102, 0], + [102, 2], + ]); + }); + + it('keeps column indexes zero-based when copying rows with rowStart', async () => { + const outerRef = { current: document.createElement('div') }; + + await copyGridElements({ + cell: Cell, + selection: { + type: 'rows', + rows: new Set([101, 100]), + anchorRow: 101, + }, + rowCount: 3, + columnCount: 2, + rowStart: 100, + focus: { row: 100, column: 0 }, + outerRef, + }); + + expect(renderedCells).toEqual([ + [100, 0], + [100, 1], + [101, 0], + [101, 1], + ]); + }); }); diff --git a/src/components/Grid/copyGridElements.ts b/src/components/Grid/copyGridElements.ts index 8f2e22386..78d67091a 100644 --- a/src/components/Grid/copyGridElements.ts +++ b/src/components/Grid/copyGridElements.ts @@ -8,7 +8,7 @@ interface CopyGridElementsProps { selection: SelectedRegion; rowCount: number; columnCount: number; - pageStart?: number; + rowStart?: number; focus: SelectionFocus; outerRef: RefObject; } @@ -53,7 +53,7 @@ const copyGridElements = async ({ selection, rowCount, columnCount, - pageStart = 0, + rowStart = 0, focus, outerRef, }: CopyGridElementsProps): Promise => { @@ -84,7 +84,7 @@ const copyGridElements = async ({ }); break; case 'columns': - Array.from({ length: rowCount }, (_, index) => pageStart + index).forEach( + Array.from({ length: rowCount }, (_, index) => rowStart + index).forEach( rowIndex => { const columnList = [...selection.columns].sort((a, b) => a - b); columnListLoop(tbody, columnList, cell, rowIndex); @@ -95,10 +95,7 @@ const copyGridElements = async ({ [...selection.rows] .sort((a, b) => a - b) .forEach(rowIndex => { - const columnList = Array.from( - { length: columnCount }, - (_, index) => pageStart + index - ); + const columnList = Array.from({ length: columnCount }, (_, index) => index); columnListLoop(tbody, columnList, cell, rowIndex); }); break;