From 8b9db6f06df4712b4cc8d4ee554b2bbca9bbe2d6 Mon Sep 17 00:00:00 2001 From: Maxime Blanchard Date: Mon, 25 Oct 2021 17:51:12 +0200 Subject: [PATCH 1/8] add: shouldCloseEdior --- src/DataGrid.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/DataGrid.tsx b/src/DataGrid.tsx index 10bed3a434..5e24eeeca0 100644 --- a/src/DataGrid.tsx +++ b/src/DataGrid.tsx @@ -156,6 +156,9 @@ export interface DataGridProps extends Sha /** * Miscellaneous */ + shouldCloseEdior?: Maybe< + (column: CalculatedColumn, currentlyEditedRow: R, incomingRow: R) => boolean + >; rowRenderer?: Maybe>>; noRowsFallback?: React.ReactNode; rowClass?: Maybe<(row: R) => Maybe>; @@ -202,6 +205,7 @@ function DataGrid( cellNavigationMode: rawCellNavigationMode, enableVirtualization, // Miscellaneous + shouldCloseEdior, rowRenderer, noRowsFallback, className, @@ -885,7 +889,10 @@ function DataGrid( } }; - if (rows[selectedPosition.rowIdx] !== selectedPosition.originalRow) { + if ( + !isGroupRow(rows[selectedPosition.rowIdx]) && + shouldCloseEdior?.(column, selectedPosition.originalRow, rows[selectedPosition.rowIdx] as R) + ) { // Discard changes if rows are updated from outside closeEditor(); } From aad0a16dc29323da372a0025d22e10786d290bb5 Mon Sep 17 00:00:00 2001 From: Maxime Blanchard Date: Wed, 27 Oct 2021 14:42:32 +0200 Subject: [PATCH 2/8] revert: onSelectedCellChange --- README.md | 2 + src/DataGrid.tsx | 5 + src/DataGridNew.tsx | 1133 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1140 insertions(+) create mode 100644 src/DataGridNew.tsx diff --git a/README.md b/README.md index 0962f2ad35..259c108959 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,8 @@ A number defining the height of summary rows. ###### `onColumnResize?: Maybe<(idx: number, width: number) => void>` +###### `onSelectedCellChange?: Maybe<(position: Position) => void>` + ###### `cellNavigationMode?: Maybe` ###### `enableVirtualization?: Maybe` diff --git a/src/DataGrid.tsx b/src/DataGrid.tsx index 5e24eeeca0..c2021379c6 100644 --- a/src/DataGrid.tsx +++ b/src/DataGrid.tsx @@ -144,6 +144,8 @@ export interface DataGridProps extends Sha onScroll?: Maybe<(event: React.UIEvent) => void>; /** Called when a column is resized */ onColumnResize?: Maybe<(idx: number, width: number) => void>; + /** Function called whenever selected cell is changed */ + onSelectedCellChange?: Maybe<(position: Position) => void>; /** * Toggles and modes @@ -199,6 +201,7 @@ function DataGrid( onRowDoubleClick, onScroll, onColumnResize, + onSelectedCellChange, onFill, onPaste, // Toggles and modes @@ -668,12 +671,14 @@ function DataGrid( if (enableEditor && isCellEditable(position)) { const row = rows[position.rowIdx] as R; setSelectedPosition({ ...position, mode: 'EDIT', row, originalRow: row }); + onSelectedCellChange?.(position); } else if (isSamePosition(selectedPosition, position)) { // Avoid re-renders if the selected cell state is the same // TODO: replace with a #record? https://github.com/microsoft/TypeScript/issues/39831 scrollToCell(position); } else { setSelectedPosition({ ...position, mode: 'SELECT' }); + onSelectedCellChange?.(position); } } diff --git a/src/DataGridNew.tsx b/src/DataGridNew.tsx new file mode 100644 index 0000000000..ca7b93ba0c --- /dev/null +++ b/src/DataGridNew.tsx @@ -0,0 +1,1133 @@ +import { + forwardRef, + useState, + useRef, + useImperativeHandle, + useCallback, + // useMemo, + useEffect +} from 'react'; +import type { Key, RefAttributes } from 'react'; +import clsx from 'clsx'; + +import { rootClassname, viewportDraggingClassname } from './style'; +import { + useLayoutEffect, + useGridDimensions, + useCalculatedColumns, + // useViewportColumns, + useViewportRows + // useLatestFunc, + // RowSelectionChangeProvider +} from './hooks'; +// import HeaderRow from './HeaderRow'; +// import Row from './Row'; +// import GroupRowRenderer from './GroupRow'; +// import SummaryRow from './SummaryRow'; +// import EditCell from './EditCell'; +// import DragHandle from './DragHandle'; +import { + // assertIsValidKeyGetter, + // getNextSelectedCellPosition, + isSelectedCellEditable, + // canExitGrid, + // isCtrlKeyHeldDown, + // isDefaultCellInput, + // getColSpan, + // max, + // sign, + getSelectedCellColSpan +} from './utils'; + +import type { + CalculatedColumn, + Column, + Position, + RowRendererProps, + RowsChangeData, + // SelectRowEvent, + FillEvent, + PasteEvent, + CellNavigationMode, + SortColumn, + RowHeightArgs, + Maybe +} from './types'; + +export interface SelectCellState extends Position { + readonly mode: 'SELECT'; +} + +interface EditCellState extends Position { + readonly mode: 'EDIT'; + readonly row: R; + readonly originalRow: R; +} + +type DefaultColumnOptions = Pick< + Column, + 'formatter' | 'minWidth' | 'resizable' | 'sortable' +>; + +const initialPosition: SelectCellState = { + idx: -1, + rowIdx: -2, + mode: 'SELECT' +}; + +export interface DataGridHandle { + element: HTMLDivElement | null; + scrollToColumn: (colIdx: number) => void; + scrollToRow: (rowIdx: number) => void; + selectCell: (position: Position, enableEditor?: Maybe) => void; +} + +type SharedDivProps = Pick< + React.HTMLAttributes, + 'aria-label' | 'aria-labelledby' | 'aria-describedby' | 'className' | 'style' +>; + +export interface DataGridProps extends SharedDivProps { + /** + * Grid and data Props + */ + /** An array of objects representing each column on the grid */ + columns: readonly Column[]; + /** A function called for each rendered row that should return a plain key/value pair object */ + rows: readonly R[]; + /** + * Rows to be pinned at the bottom of the rows view for summary, the vertical scroll bar will not scroll these rows. + * Bottom horizontal scroll bar can move the row left / right. Or a customized row renderer can be used to disabled the scrolling support. + */ + summaryRows?: Maybe; + /** The getter should return a unique key for each row */ + rowKeyGetter?: Maybe<(row: R) => K>; + onRowsChange?: Maybe<(rows: R[], data: RowsChangeData) => void>; + + /** + * Dimensions props + */ + /** + * The height of each row in pixels + * @default 35 + */ + rowHeight?: Maybe) => number)>; + /** + * The height of the header row in pixels + * @default 35 + */ + headerRowHeight?: Maybe; + /** + * The height of each summary row in pixels + * @default 35 + */ + summaryRowHeight?: Maybe; + + /** + * Feature props + */ + /** Set of selected row keys */ + selectedRows?: Maybe>; + /** Function called whenever row selection is changed */ + onSelectedRowsChange?: Maybe<(selectedRows: Set) => void>; + /** Used for multi column sorting */ + sortColumns?: Maybe; + onSortColumnsChange?: Maybe<(sortColumns: SortColumn[]) => void>; + defaultColumnOptions?: Maybe>; + groupBy?: Maybe; + rowGrouper?: Maybe<(rows: readonly R[], columnKey: string) => Record>; + expandedGroupIds?: Maybe>; + onExpandedGroupIdsChange?: Maybe<(expandedGroupIds: Set) => void>; + onFill?: Maybe<(event: FillEvent) => R>; + onPaste?: Maybe<(event: PasteEvent) => R>; + + /** + * Event props + */ + /** Function called whenever a row is clicked */ + onRowClick?: Maybe<(row: R, column: CalculatedColumn) => void>; + /** Function called whenever a row is double clicked */ + onRowDoubleClick?: Maybe<(row: R, column: CalculatedColumn) => void>; + /** Called when the grid is scrolled */ + onScroll?: Maybe<(event: React.UIEvent) => void>; + /** Called when a column is resized */ + onColumnResize?: Maybe<(idx: number, width: number) => void>; + + /** + * Toggles and modes + */ + /** @default 'NONE' */ + cellNavigationMode?: Maybe; + /** @default true */ + enableVirtualization?: Maybe; + + /** + * Miscellaneous + */ + shouldCloseEdior?: Maybe< + (column: CalculatedColumn, currentlyEditedRow: R, incomingRow: R) => boolean + >; + rowRenderer?: Maybe>>; + noRowsFallback?: React.ReactNode; + rowClass?: Maybe<(row: R) => Maybe>; + 'data-testid'?: Maybe; +} + +/** + * Main API Component to render a data grid of rows and columns + * + * @example + * + * + */ +function DataGrid( + { + // Grid and data Props + columns: rawColumns, + rows: rawRows, + summaryRows, + // rowKeyGetter, + onRowsChange, + // Dimensions props + rowHeight, + headerRowHeight: rawHeaderRowHeight, + summaryRowHeight: rawSummaryRowHeight, + // Feature props + selectedRows, + onSelectedRowsChange, + // sortColumns, + // onSortColumnsChange, + defaultColumnOptions, + groupBy: rawGroupBy, + rowGrouper, + expandedGroupIds, + // onExpandedGroupIdsChange, + // Event props + // onRowClick, + // onRowDoubleClick, + onScroll, + // onColumnResize, + // onFill, + // onPaste, + // Toggles and modes + // cellNavigationMode: rawCellNavigationMode, + enableVirtualization, + // Miscellaneous + // shouldCloseEdior, + // rowRenderer, + // noRowsFallback, + className, + // style, + // rowClass, + // ARIA + 'aria-label': ariaLabel, + 'aria-labelledby': ariaLabelledBy, + 'aria-describedby': ariaDescribedBy, + 'data-testid': testId + }: DataGridProps, + ref: React.Ref +) { + /** + * defaults + */ + rowHeight ??= 35; + const headerRowHeight = rawHeaderRowHeight ?? (typeof rowHeight === 'number' ? rowHeight : 35); + const summaryRowHeight = rawSummaryRowHeight ?? (typeof rowHeight === 'number' ? rowHeight : 35); + // const RowRenderer = rowRenderer ?? Row; + // const cellNavigationMode = rawCellNavigationMode ?? 'NONE'; + enableVirtualization ??= true; + + /** + * states + */ + const [scrollTop, setScrollTop] = useState(0); + const [scrollLeft, setScrollLeft] = useState(0); + const [ + columnWidths + // setColumnWidths + ] = useState>(() => new Map()); + const [selectedPosition, setSelectedPosition] = useState>( + initialPosition + ); + // const [ + // copiedCell + // setCopiedCell + // ] = useState<{ row: R; columnKey: string } | null>(null); + const [ + isDragging + // setDragging + ] = useState(false); + const [draggedOverRowIdx, setOverRowIdx] = useState(undefined); + + /** + * refs + */ + const prevSelectedPosition = useRef(selectedPosition); + const latestDraggedOverRowIdx = useRef(draggedOverRowIdx); + // const lastSelectedRowIdx = useRef(-1); + + /** + * computed values + */ + const [gridRef, gridWidth, gridHeight] = useGridDimensions(); + const headerRowsCount = 1; + const summaryRowsCount = summaryRows?.length ?? 0; + const clientHeight = gridHeight - headerRowHeight - summaryRowsCount * summaryRowHeight; + const isSelectable = selectedRows != null && onSelectedRowsChange != null; + // const isHeaderRowSelected = selectedPosition.rowIdx === -1; + + // const allRowsSelected = useMemo((): boolean => { + // // no rows to select = explicitely unchecked + // const { length } = rawRows; + // return ( + // length !== 0 && + // selectedRows != null && + // rowKeyGetter != null && + // selectedRows.size >= length && + // rawRows.every((row) => selectedRows.has(rowKeyGetter(row))) + // ); + // }, [rawRows, selectedRows, rowKeyGetter]); + + const { + columns, + // colSpanColumns, + // colOverscanStartIdx, + // colOverscanEndIdx, + // layoutCssVars, + columnMetrics, + // totalColumnWidth, + lastFrozenColumnIndex, + totalFrozenColumnWidth, + groupBy + } = useCalculatedColumns({ + rawColumns, + columnWidths, + scrollLeft, + viewportWidth: gridWidth, + defaultColumnOptions, + rawGroupBy: rowGrouper ? rawGroupBy : undefined, + enableVirtualization + }); + + const { + // rowOverscanStartIdx, + // rowOverscanEndIdx, + rows, + rowsCount, + // totalRowHeight, + isGroupRow, + getRowTop, + getRowHeight + // findRowIdx + } = useViewportRows({ + rawRows, + groupBy, + rowGrouper, + rowHeight, + clientHeight, + scrollTop, + expandedGroupIds, + enableVirtualization + }); + + // const viewportColumns = useViewportColumns({ + // columns, + // colSpanColumns, + // colOverscanStartIdx, + // colOverscanEndIdx, + // lastFrozenColumnIndex, + // rowOverscanStartIdx, + // rowOverscanEndIdx, + // rows, + // summaryRows, + // isGroupRow + // }); + + const hasGroups = groupBy.length > 0 && typeof rowGrouper === 'function'; + const minColIdx = hasGroups ? -1 : 0; + const maxColIdx = columns.length - 1; + const minRowIdx = -1; // change it to 0? + const maxRowIdx = headerRowsCount + rows.length + summaryRowsCount - 2; + const selectedCellIsWithinSelectionBounds = isCellWithinSelectionBounds(selectedPosition); + // const selectedCellIsWithinViewportBounds = isCellWithinViewportBounds(selectedPosition); + + useEffect(() => { + console.log('react-data-grid v6'); + }, []); + + /** + * The identity of the wrapper function is stable so it won't break memoization + */ + // const selectRowLatest = useLatestFunc(selectRow); + // const selectAllRowsLatest = useLatestFunc(selectAllRows); + // const handleFormatterRowChangeLatest = useLatestFunc(updateRow); + // const selectViewportCellLatest = useLatestFunc( + // (row: R, column: CalculatedColumn, enableEditor: Maybe) => { + // const rowIdx = rows.indexOf(row); + // selectCell({ rowIdx, idx: column.idx }, enableEditor); + // } + // ); + // const selectGroupLatest = useLatestFunc((rowIdx: number) => { + // selectCell({ rowIdx, idx: -1 }); + // }); + // const selectHeaderCellLatest = useLatestFunc((idx: number) => { + // selectCell({ rowIdx: -1, idx }); + // }); + // const selectSummaryCellLatest = useLatestFunc( + // (summaryRow: SR, column: CalculatedColumn) => { + // const rowIdx = summaryRows!.indexOf(summaryRow) + headerRowsCount + rows.length - 1; + // selectCell({ rowIdx, idx: column.idx }); + // } + // ); + // const toggleGroupLatest = useLatestFunc(toggleGroup); + + /** + * effects + */ + useLayoutEffect(() => { + if ( + !selectedCellIsWithinSelectionBounds || + isSamePosition(selectedPosition, prevSelectedPosition.current) + ) { + prevSelectedPosition.current = selectedPosition; + return; + } + + prevSelectedPosition.current = selectedPosition; + scrollToCell(selectedPosition); + }); + + useImperativeHandle(ref, () => ({ + element: gridRef.current, + scrollToColumn(idx: number) { + scrollToCell({ idx }); + }, + scrollToRow(rowIdx: number) { + const { current } = gridRef; + if (!current) return; + current.scrollTo({ + top: getRowTop(rowIdx), + behavior: 'smooth' + }); + }, + selectCell + })); + + /** + * callbacks + */ + // const handleColumnResize = useCallback( + // (column: CalculatedColumn, width: number) => { + // setColumnWidths((columnWidths) => { + // const newColumnWidths = new Map(columnWidths); + // newColumnWidths.set(column.key, width); + // return newColumnWidths; + // }); + + // onColumnResize?.(column.idx, width); + // }, + // [onColumnResize] + // ); + + const setDraggedOverRowIdx = useCallback((rowIdx?: number) => { + setOverRowIdx(rowIdx); + latestDraggedOverRowIdx.current = rowIdx; + }, []); + + /** + * event handlers + */ + // function selectRow({ row, checked, isShiftClick }: SelectRowEvent) { + // if (!onSelectedRowsChange) return; + + // assertIsValidKeyGetter(rowKeyGetter); + // const newSelectedRows = new Set(selectedRows); + // if (isGroupRow(row)) { + // for (const childRow of row.childRows) { + // const rowKey = rowKeyGetter(childRow); + // if (checked) { + // newSelectedRows.add(rowKey); + // } else { + // newSelectedRows.delete(rowKey); + // } + // } + // onSelectedRowsChange(newSelectedRows); + // return; + // } + + // const rowKey = rowKeyGetter(row); + // if (checked) { + // newSelectedRows.add(rowKey); + // const previousRowIdx = lastSelectedRowIdx.current; + // const rowIdx = rows.indexOf(row); + // lastSelectedRowIdx.current = rowIdx; + // if (isShiftClick && previousRowIdx !== -1 && previousRowIdx !== rowIdx) { + // const step = sign(rowIdx - previousRowIdx); + // for (let i = previousRowIdx + step; i !== rowIdx; i += step) { + // const row = rows[i]; + // if (isGroupRow(row)) continue; + // newSelectedRows.add(rowKeyGetter(row)); + // } + // } + // } else { + // newSelectedRows.delete(rowKey); + // lastSelectedRowIdx.current = -1; + // } + + // onSelectedRowsChange(newSelectedRows); + // } + + // function selectAllRows(checked: boolean) { + // if (!onSelectedRowsChange) return; + + // assertIsValidKeyGetter(rowKeyGetter); + // const newSelectedRows = new Set(selectedRows); + + // for (const row of rawRows) { + // const rowKey = rowKeyGetter(row); + // if (checked) { + // newSelectedRows.add(rowKey); + // } else { + // newSelectedRows.delete(rowKey); + // } + // } + + // onSelectedRowsChange(newSelectedRows); + // } + + // function toggleGroup(expandedGroupId: unknown) { + // if (!onExpandedGroupIdsChange) return; + // const newExpandedGroupIds = new Set(expandedGroupIds); + // if (newExpandedGroupIds.has(expandedGroupId)) { + // newExpandedGroupIds.delete(expandedGroupId); + // } else { + // newExpandedGroupIds.add(expandedGroupId); + // } + // onExpandedGroupIdsChange(newExpandedGroupIds); + // } + + // function _handleKeyDown(event: React.KeyboardEvent) { + // if (!(event.target instanceof Element)) return; + // const isCellEvent = event.target.closest('.rdg-cell') !== null; + // const isRowEvent = hasGroups && event.target.matches('.rdg-row, .rdg-header-row'); + // if (!isCellEvent && !isRowEvent) return; + + // const { key, keyCode } = event; + // const { rowIdx } = selectedPosition; + + // if ( + // selectedCellIsWithinViewportBounds && + // // onPaste != null && + // isCtrlKeyHeldDown(event) && + // !isGroupRow(rows[rowIdx]) && + // selectedPosition.mode === 'SELECT' + // ) { + // // event.key may differ by keyboard input language, so we use event.keyCode instead + // // event.nativeEvent.code cannot be used either as it would break copy/paste for the DVORAK layout + // const cKey = 67; + // const vKey = 86; + // if (keyCode === cKey) { + // handleCopy(); + // return; + // } + // if (keyCode === vKey) { + // handlePaste(); + // return; + // } + // } + + // if (isRowIdxWithinViewportBounds(rowIdx)) { + // const row = rows[rowIdx]; + + // if ( + // isGroupRow(row) && + // selectedPosition.idx === -1 && + // // Collapse the current group row if it is focused and is in expanded state + // ((key === 'ArrowLeft' && row.isExpanded) || + // // Expand the current group row if it is focused and is in collapsed state + // (key === 'ArrowRight' && !row.isExpanded)) + // ) { + // event.preventDefault(); // Prevents scrolling + // toggleGroup(row.id); + // return; + // } + // } + + // switch (event.key) { + // case 'Escape': + // setCopiedCell(null); + // return; + // case 'ArrowUp': + // case 'ArrowDown': + // case 'ArrowLeft': + // case 'ArrowRight': + // case 'Tab': + // case 'Home': + // case 'End': + // case 'PageUp': + // case 'PageDown': + // navigate(event); + // break; + // default: + // handleCellInput(event); + // break; + // } + // } + + function handleScroll(event: React.UIEvent) { + const { scrollTop, scrollLeft } = event.currentTarget; + setScrollTop(scrollTop); + setScrollLeft(scrollLeft); + onScroll?.(event); + } + + function getRawRowIdx(rowIdx: number) { + return hasGroups ? rawRows.indexOf(rows[rowIdx] as R) : rowIdx; + } + + function updateRow(rowIdx: number, row: R) { + if (typeof onRowsChange !== 'function') return; + const rawRowIdx = getRawRowIdx(rowIdx); + if (row === rawRows[rawRowIdx]) return; + const updatedRows = [...rawRows]; + updatedRows[rawRowIdx] = row; + onRowsChange(updatedRows, { + indexes: [rawRowIdx], + column: columns[selectedPosition.idx] + }); + } + + function commitEditorChanges() { + if (selectedPosition.mode !== 'EDIT') return; + updateRow(selectedPosition.rowIdx, selectedPosition.row); + } + + // function handleCopy() { + // const { idx, rowIdx } = selectedPosition; + // setCopiedCell({ row: rawRows[getRawRowIdx(rowIdx)], columnKey: columns[idx].key }); + // } + + // function handlePaste() { + // if (!onPaste || !onRowsChange || copiedCell === null || !isCellEditable(selectedPosition)) { + // return; + // } + + // const { idx, rowIdx } = selectedPosition; + // const targetRow = rawRows[getRawRowIdx(rowIdx)]; + + // const updatedTargetRow = onPaste({ + // sourceRow: copiedCell.row, + // sourceColumnKey: copiedCell.columnKey, + // targetRow, + // targetColumnKey: columns[idx].key + // }); + + // updateRow(rowIdx, updatedTargetRow); + // } + + // function handleCellInput(event: React.KeyboardEvent) { + // if (!selectedCellIsWithinViewportBounds) return; + // const row = rows[selectedPosition.rowIdx]; + // if (isGroupRow(row)) return; + // const { key, shiftKey } = event; + + // // Select the row on Shift + Space + // if (isSelectable && shiftKey && key === ' ') { + // assertIsValidKeyGetter(rowKeyGetter); + // const rowKey = rowKeyGetter(row); + // selectRow({ row, checked: !selectedRows.has(rowKey), isShiftClick: false }); + // // do not scroll + // event.preventDefault(); + // return; + // } + + // const column = columns[selectedPosition.idx]; + // column.editorOptions?.onCellKeyDown?.(event); + // if (event.isDefaultPrevented()) return; + + // if (isCellEditable(selectedPosition) && isDefaultCellInput(event)) { + // setSelectedPosition(({ idx, rowIdx }) => ({ + // idx, + // rowIdx, + // mode: 'EDIT', + // row, + // originalRow: row + // })); + // } + // } + + /** + * utils + */ + function isColIdxWithinSelectionBounds(idx: number) { + return idx >= minColIdx && idx <= maxColIdx; + } + + function isRowIdxWithinViewportBounds(rowIdx: number) { + return rowIdx >= 0 && rowIdx < rows.length; + } + + function isCellWithinSelectionBounds({ idx, rowIdx }: Position): boolean { + return rowIdx >= minRowIdx && rowIdx <= maxRowIdx && isColIdxWithinSelectionBounds(idx); + } + + function isCellWithinViewportBounds({ idx, rowIdx }: Position): boolean { + return isRowIdxWithinViewportBounds(rowIdx) && isColIdxWithinSelectionBounds(idx); + } + + function isCellEditable(position: Position): boolean { + return ( + isCellWithinViewportBounds(position) && + isSelectedCellEditable({ columns, rows, selectedPosition: position, isGroupRow }) + ); + } + + function selectCell(position: Position, enableEditor?: Maybe): void { + if (!isCellWithinSelectionBounds(position)) return; + commitEditorChanges(); + + if (enableEditor && isCellEditable(position)) { + const row = rows[position.rowIdx] as R; + setSelectedPosition({ ...position, mode: 'EDIT', row, originalRow: row }); + } else if (isSamePosition(selectedPosition, position)) { + // Avoid re-renders if the selected cell state is the same + // TODO: replace with a #record? https://github.com/microsoft/TypeScript/issues/39831 + scrollToCell(position); + } else { + setSelectedPosition({ ...position, mode: 'SELECT' }); + } + } + + function scrollToCell({ idx, rowIdx }: Partial): void { + const { current } = gridRef; + if (!current) return; + + if (typeof idx === 'number' && idx > lastFrozenColumnIndex) { + rowIdx ??= selectedPosition.rowIdx; + if (!isCellWithinSelectionBounds({ rowIdx, idx })) return; + const { clientWidth } = current; + const column = columns[idx]; + const { left, width } = columnMetrics.get(column)!; + let right = left + width; + + const colSpan = getSelectedCellColSpan({ + rows, + summaryRows, + rowIdx, + lastFrozenColumnIndex, + column, + isGroupRow + }); + + if (colSpan !== undefined) { + const { left, width } = columnMetrics.get(columns[column.idx + colSpan - 1])!; + right = left + width; + } + + const isCellAtLeftBoundary = left < scrollLeft + totalFrozenColumnWidth; + const isCellAtRightBoundary = right > clientWidth + scrollLeft; + if (isCellAtLeftBoundary) { + current.scrollLeft = left - totalFrozenColumnWidth; + } else if (isCellAtRightBoundary) { + current.scrollLeft = right - clientWidth; + } + } + + if (typeof rowIdx === 'number' && isRowIdxWithinViewportBounds(rowIdx)) { + const rowTop = getRowTop(rowIdx); + const rowHeight = getRowHeight(rowIdx); + if (rowTop < scrollTop) { + // at top boundary, scroll to the row's top + current.scrollTop = rowTop; + } else if (rowTop + rowHeight > scrollTop + clientHeight) { + // at bottom boundary, scroll the next row's top to the bottom of the viewport + current.scrollTop = rowTop + rowHeight - clientHeight; + } + } + } + + // function getNextPosition(key: string, ctrlKey: boolean, shiftKey: boolean): Position { + // const { idx, rowIdx } = selectedPosition; + // const row = rows[rowIdx]; + // const isRowSelected = selectedCellIsWithinSelectionBounds && idx === -1; + + // // If a group row is focused, and it is collapsed, move to the parent group row (if there is one). + // if ( + // key === 'ArrowLeft' && + // isRowSelected && + // isGroupRow(row) && + // !row.isExpanded && + // row.level !== 0 + // ) { + // let parentRowIdx = -1; + // for (let i = selectedPosition.rowIdx - 1; i >= 0; i--) { + // const parentRow = rows[i]; + // if (isGroupRow(parentRow) && parentRow.id === row.parentId) { + // parentRowIdx = i; + // break; + // } + // } + // if (parentRowIdx !== -1) { + // return { idx, rowIdx: parentRowIdx }; + // } + // } + + // switch (key) { + // case 'ArrowUp': + // return { idx, rowIdx: rowIdx - 1 }; + // case 'ArrowDown': + // return { idx, rowIdx: rowIdx + 1 }; + // case 'ArrowLeft': + // return { idx: idx - 1, rowIdx }; + // case 'ArrowRight': + // return { idx: idx + 1, rowIdx }; + // case 'Tab': + // return { idx: idx + (shiftKey ? -1 : 1), rowIdx }; + // case 'Home': + // // If row is selected then move focus to the first row + // if (isRowSelected) return { idx, rowIdx: 0 }; + // return { idx: 0, rowIdx: ctrlKey ? minRowIdx : rowIdx }; + // case 'End': + // // If row is selected then move focus to the last row. + // if (isRowSelected) return { idx, rowIdx: rows.length - 1 }; + // return { idx: maxColIdx, rowIdx: ctrlKey ? maxRowIdx : rowIdx }; + // case 'PageUp': { + // if (selectedPosition.rowIdx === minRowIdx) return selectedPosition; + // const nextRowY = getRowTop(rowIdx) + getRowHeight(rowIdx) - clientHeight; + // return { idx, rowIdx: nextRowY > 0 ? findRowIdx(nextRowY) : 0 }; + // } + // case 'PageDown': { + // if (selectedPosition.rowIdx >= rows.length) return selectedPosition; + // const nextRowY = getRowTop(rowIdx) + clientHeight; + // return { idx, rowIdx: nextRowY < totalRowHeight ? findRowIdx(nextRowY) : rows.length - 1 }; + // } + // default: + // return selectedPosition; + // } + // } + + // function navigate(event: React.KeyboardEvent) { + // const { key, shiftKey } = event; + // let mode = cellNavigationMode; + // if (key === 'Tab') { + // if ( + // canExitGrid({ + // shiftKey, + // cellNavigationMode, + // maxColIdx, + // minRowIdx, + // maxRowIdx, + // selectedPosition + // }) + // ) { + // commitEditorChanges(); + // // Allow focus to leave the grid so the next control in the tab order can be focused + // return; + // } + + // mode = cellNavigationMode === 'NONE' ? 'CHANGE_ROW' : cellNavigationMode; + // } + + // // Do not allow focus to leave + // event.preventDefault(); + + // const ctrlKey = isCtrlKeyHeldDown(event); + // const nextPosition = getNextPosition(key, ctrlKey, shiftKey); + // if (isSamePosition(selectedPosition, nextPosition)) return; + + // const nextSelectedCellPosition = getNextSelectedCellPosition({ + // columns, + // colSpanColumns, + // rows, + // summaryRows, + // minRowIdx, + // maxRowIdx, + // lastFrozenColumnIndex, + // cellNavigationMode: mode, + // currentPosition: selectedPosition, + // nextPosition, + // isCellWithinBounds: isCellWithinSelectionBounds, + // isGroupRow + // }); + + // selectCell(nextSelectedCellPosition); + // } + + // function getDraggedOverCellIdx(currentRowIdx: number): number | undefined { + // if (draggedOverRowIdx === undefined) return; + // const { rowIdx } = selectedPosition; + + // const isDraggedOver = + // rowIdx < draggedOverRowIdx + // ? rowIdx < currentRowIdx && currentRowIdx <= draggedOverRowIdx + // : rowIdx > currentRowIdx && currentRowIdx >= draggedOverRowIdx; + + // return isDraggedOver ? selectedPosition.idx : undefined; + // } + + // function getDragHandle(rowIdx: number) { + // if ( + // selectedPosition.rowIdx !== rowIdx || + // selectedPosition.mode === 'EDIT' || + // hasGroups || // drag fill is not supported when grouping is enabled + // onFill == null + // ) { + // return; + // } + + // return ( + // + // ); + // } + + // function getCellEditor(rowIdx: number) { + // if (selectedPosition.rowIdx !== rowIdx || selectedPosition.mode === 'SELECT') return; + + // const { idx, row } = selectedPosition; + // const column = columns[idx]; + // const colSpan = getColSpan(column, lastFrozenColumnIndex, { type: 'ROW', row }); + + // const closeEditor = () => { + // setSelectedPosition(({ idx, rowIdx }) => ({ idx, rowIdx, mode: 'SELECT' })); + // }; + + // const onRowChange = (row: R, commitChanges?: boolean) => { + // if (commitChanges) { + // updateRow(selectedPosition.rowIdx, row); + // closeEditor(); + // } else { + // setSelectedPosition((position) => ({ ...position, row })); + // } + // }; + + // if ( + // !isGroupRow(rows[selectedPosition.rowIdx]) && + // shouldCloseEdior?.(column, selectedPosition.originalRow, rows[selectedPosition.rowIdx] as R) + // ) { + // // Discard changes if rows are updated from outside + // closeEditor(); + // } + + // return ( + // { + // scrollToCell(selectedPosition); + // }} + // /> + // ); + // } + + // function getViewportRows() { + // const rowElements = []; + // let startRowIndex = 0; + + // const { idx: selectedIdx, rowIdx: selectedRowIdx } = selectedPosition; + // const startRowIdx = + // selectedCellIsWithinViewportBounds && selectedRowIdx < rowOverscanStartIdx + // ? rowOverscanStartIdx - 1 + // : rowOverscanStartIdx; + // const endRowIdx = + // selectedCellIsWithinViewportBounds && selectedRowIdx > rowOverscanEndIdx + // ? rowOverscanEndIdx + 1 + // : rowOverscanEndIdx; + + // for (let viewportRowIdx = startRowIdx; viewportRowIdx <= endRowIdx; viewportRowIdx++) { + // const isRowOutsideViewport = + // viewportRowIdx === rowOverscanStartIdx - 1 || viewportRowIdx === rowOverscanEndIdx + 1; + // const rowIdx = isRowOutsideViewport ? selectedRowIdx : viewportRowIdx; + + // let rowColumns = viewportColumns; + // const selectedColumn = columns[selectedIdx]; + // // selectedIdx can be -1 if grouping is enabled + // // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + // if (selectedColumn !== undefined) { + // if (isRowOutsideViewport) { + // // if the row is outside the viewport then only render the selected cell + // rowColumns = [selectedColumn]; + // } else if (selectedRowIdx === rowIdx && !viewportColumns.includes(selectedColumn)) { + // // if the row is within the viewport and cell is not, add the selected column to viewport columns + // rowColumns = + // selectedIdx > viewportColumns[viewportColumns.length - 1].idx + // ? [...viewportColumns, selectedColumn] + // : [ + // ...viewportColumns.slice(0, lastFrozenColumnIndex + 1), + // selectedColumn, + // ...viewportColumns.slice(lastFrozenColumnIndex + 1) + // ]; + // } + // } + + // const row = rows[rowIdx]; + // const top = getRowTop(rowIdx) + headerRowHeight; + // if (isGroupRow(row)) { + // ({ startRowIndex } = row); + // const isGroupRowSelected = + // isSelectable && row.childRows.every((cr) => selectedRows.has(rowKeyGetter!(cr))); + // rowElements.push( + // + // ); + // continue; + // } + + // startRowIndex++; + // let key; + // let isRowSelected = false; + // if (typeof rowKeyGetter === 'function') { + // key = rowKeyGetter(row); + // isRowSelected = selectedRows?.has(key) ?? false; + // } else { + // key = hasGroups ? startRowIndex : rowIdx; + // } + + // rowElements.push( + // c.key === copiedCell.columnKey) + // : undefined + // } + // selectedCellIdx={selectedRowIdx === rowIdx ? selectedIdx : undefined} + // draggedOverCellIdx={getDraggedOverCellIdx(rowIdx)} + // setDraggedOverRowIdx={isDragging ? setDraggedOverRowIdx : undefined} + // lastFrozenColumnIndex={lastFrozenColumnIndex} + // onRowChange={handleFormatterRowChangeLatest} + // selectCell={selectViewportCellLatest} + // selectedCellDragHandle={getDragHandle(rowIdx)} + // selectedCellEditor={getCellEditor(rowIdx)} + // /> + // ); + // } + + // return rowElements; + // } + + // Reset the positions if the current values are no longer valid. This can happen if a column or row is removed + if (selectedPosition.idx > maxColIdx || selectedPosition.rowIdx > maxRowIdx) { + setSelectedPosition(initialPosition); + setDraggedOverRowIdx(undefined); + } + + return ( +
+
+ {/* + {rows.length === 0 && noRowsFallback ? ( + noRowsFallback + ) : ( + <> +
+ + {getViewportRows()} + + {summaryRows?.map((row, rowIdx) => { + const isSummaryRowSelected = + selectedPosition.rowIdx === headerRowsCount + rows.length + rowIdx - 1; + return ( + + ); + })} + + )} */} +
+ ); +} + +function isSamePosition(p1: Position, p2: Position) { + return p1.idx === p2.idx && p1.rowIdx === p2.rowIdx; +} + +export default forwardRef(DataGrid) as ( + props: DataGridProps & RefAttributes +) => JSX.Element; From 8b1389b42ca7fb7d8da4f5af0ae8b391a6b18ccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Boussus?= Date: Thu, 27 Oct 2022 17:23:26 +0200 Subject: [PATCH 3/8] fixed typo of shouldCloseEditor --- src/DataGridNew.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/DataGridNew.tsx b/src/DataGridNew.tsx index ca7b93ba0c..0415229fbe 100644 --- a/src/DataGridNew.tsx +++ b/src/DataGridNew.tsx @@ -164,7 +164,7 @@ export interface DataGridProps extends Sha /** * Miscellaneous */ - shouldCloseEdior?: Maybe< + shouldCloseEditor?: Maybe< (column: CalculatedColumn, currentlyEditedRow: R, incomingRow: R) => boolean >; rowRenderer?: Maybe>>; @@ -213,7 +213,7 @@ function DataGrid( // cellNavigationMode: rawCellNavigationMode, enableVirtualization, // Miscellaneous - // shouldCloseEdior, + // shouldCloseEditor, // rowRenderer, // noRowsFallback, className, @@ -912,7 +912,7 @@ function DataGrid( // if ( // !isGroupRow(rows[selectedPosition.rowIdx]) && - // shouldCloseEdior?.(column, selectedPosition.originalRow, rows[selectedPosition.rowIdx] as R) + // shouldCloseEditor?.(column, selectedPosition.originalRow, rows[selectedPosition.rowIdx] as R) // ) { // // Discard changes if rows are updated from outside // closeEditor(); From e8f0946cb0f392969bbce04e8dded14d6df241ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Boussus?= Date: Thu, 27 Oct 2022 17:31:57 +0200 Subject: [PATCH 4/8] add lib --- lib/bundle.cjs | 2851 ++++++++++++++++++++++++++++++++++++++++++++ lib/bundle.cjs.map | 1 + lib/bundle.js | 2832 +++++++++++++++++++++++++++++++++++++++++++ lib/bundle.js.map | 1 + lib/index.d.ts | 384 ++++++ lib/styles.css | 444 +++++++ 6 files changed, 6513 insertions(+) create mode 100644 lib/bundle.cjs create mode 100644 lib/bundle.cjs.map create mode 100644 lib/bundle.js create mode 100644 lib/bundle.js.map create mode 100644 lib/index.d.ts create mode 100644 lib/styles.css diff --git a/lib/bundle.cjs b/lib/bundle.cjs new file mode 100644 index 0000000000..69bcdda186 --- /dev/null +++ b/lib/bundle.cjs @@ -0,0 +1,2851 @@ +'use strict'; + +Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } }); + +const react = require('react'); +const reactDom = require('react-dom'); +const clsx = require('clsx'); +const jsxRuntime = require('react/jsx-runtime'); + +const cell = "cj343x07-0-0-beta-19"; +const cellClassname = `rdg-cell ${cell}`; +const cellFrozen = "csofj7r7-0-0-beta-19"; +const cellFrozenClassname = `rdg-cell-frozen ${cellFrozen}`; +const cellFrozenLast = "ch2wcw87-0-0-beta-19"; +const cellFrozenLastClassname = `rdg-cell-frozen-last ${cellFrozenLast}`; + +const root = "rnvodz57-0-0-beta-19"; +const rootClassname = `rdg ${root}`; +const viewportDragging = "vlqv91k7-0-0-beta-19"; +const viewportDraggingClassname = `rdg-viewport-dragging ${viewportDragging}`; +const focusSinkClassname = "f1lsfrzw7-0-0-beta-19"; + +const row = "r1upfr807-0-0-beta-19"; +const rowClassname = `rdg-row ${row}`; +const rowSelected = "r190mhd37-0-0-beta-19"; +const rowSelectedClassname = `rdg-row-selected`; +const rowSelectedWithFrozenCell = "r139qu9m7-0-0-beta-19"; + +const checkboxLabel = "c1xpveok7-0-0-beta-19"; +const checkboxLabelClassname = `rdg-checkbox-label ${checkboxLabel}`; +const checkboxInput = "c18qzqt57-0-0-beta-19"; +const checkboxInputClassname = `rdg-checkbox-input ${checkboxInput}`; +const checkbox = "c1pjjz6k7-0-0-beta-19"; +const checkboxClassname = `rdg-checkbox ${checkbox}`; +const checkboxLabelDisabled = "c33qujk7-0-0-beta-19"; +const checkboxLabelDisabledClassname = `rdg-checkbox-label-disabled ${checkboxLabelDisabled}`; +function checkboxFormatter({ + onChange, + ...props +}, ref) { + function handleChange(e) { + onChange(e.target.checked, e.nativeEvent.shiftKey); + } + return /*#__PURE__*/jsxRuntime.jsxs("label", { + className: clsx(checkboxLabelClassname, props.disabled && checkboxLabelDisabledClassname), + children: [/*#__PURE__*/jsxRuntime.jsx("input", { + type: "checkbox", + ref: ref, + ...props, + className: checkboxInputClassname, + onChange: handleChange + }), /*#__PURE__*/jsxRuntime.jsx("div", { + className: checkboxClassname + })] + }); +} + +const useLayoutEffect = typeof window === 'undefined' ? react.useEffect : react.useLayoutEffect; + +function useFocusRef(isSelected) { + const ref = react.useRef(null); + useLayoutEffect(() => { + if (!isSelected) return; + ref.current?.focus({ + preventScroll: true + }); + }, [isSelected]); + return { + ref, + tabIndex: isSelected ? 0 : -1 + }; +} + +const DataGridDefaultComponentsContext = /*#__PURE__*/react.createContext(undefined); +const DataGridDefaultComponentsProvider = DataGridDefaultComponentsContext.Provider; +function useDefaultComponents() { + return react.useContext(DataGridDefaultComponentsContext); +} + +function SelectCellFormatter({ + value, + isCellSelected, + disabled, + onChange, + 'aria-label': ariaLabel, + 'aria-labelledby': ariaLabelledBy +}) { + const { + ref, + tabIndex + } = useFocusRef(isCellSelected); + const checkboxFormatter = useDefaultComponents().checkboxFormatter; + return /*#__PURE__*/jsxRuntime.jsx(jsxRuntime.Fragment, { + children: checkboxFormatter({ + 'aria-label': ariaLabel, + 'aria-labelledby': ariaLabelledBy, + tabIndex, + disabled, + checked: value, + onChange + }, ref) + }); +} + +function valueFormatter(props) { + try { + return /*#__PURE__*/jsxRuntime.jsx(jsxRuntime.Fragment, { + children: props.row[props.column.key] + }); + } catch { + return null; + } +} + +const groupCellContent = "gnionrs7-0-0-beta-19"; +const groupCellContentClassname = `rdg-group-cell-content ${groupCellContent}`; +const caret = "c18nrzwp7-0-0-beta-19"; +const caretClassname = `rdg-caret ${caret}`; +function toggleGroupFormatter(props) { + return /*#__PURE__*/jsxRuntime.jsx(ToggleGroup, { + ...props + }); +} +function ToggleGroup({ + groupKey, + isExpanded, + isCellSelected, + toggleGroup +}) { + const { + ref, + tabIndex + } = useFocusRef(isCellSelected); + function handleKeyDown({ + key + }) { + if (key === 'Enter') { + toggleGroup(); + } + } + const d = isExpanded ? 'M1 1 L 7 7 L 13 1' : 'M1 7 L 7 1 L 13 7'; + return /*#__PURE__*/jsxRuntime.jsxs("span", { + ref: ref, + className: groupCellContentClassname, + tabIndex: tabIndex, + onKeyDown: handleKeyDown, + children: [groupKey, /*#__PURE__*/jsxRuntime.jsx("svg", { + viewBox: "0 0 14 8", + width: "14", + height: "8", + className: caretClassname, + "aria-hidden": true, + children: /*#__PURE__*/jsxRuntime.jsx("path", { + d: d + }) + })] + }); +} + +const RowSelectionContext = /*#__PURE__*/react.createContext(undefined); +const RowSelectionProvider = RowSelectionContext.Provider; +const RowSelectionChangeContext = /*#__PURE__*/react.createContext(undefined); +const RowSelectionChangeProvider = RowSelectionChangeContext.Provider; +function useRowSelection() { + const rowSelectionContext = react.useContext(RowSelectionContext); + const rowSelectionChangeContext = react.useContext(RowSelectionChangeContext); + if (rowSelectionContext === undefined || rowSelectionChangeContext === undefined) { + throw new Error('useRowSelection must be used within DataGrid cells'); + } + return [rowSelectionContext, rowSelectionChangeContext]; +} + +const SELECT_COLUMN_KEY = 'select-row'; +function SelectFormatter(props) { + const [isRowSelected, onRowSelectionChange] = useRowSelection(); + return /*#__PURE__*/jsxRuntime.jsx(SelectCellFormatter, { + "aria-label": "Select", + isCellSelected: props.isCellSelected, + value: isRowSelected, + onChange: (checked, isShiftClick) => { + onRowSelectionChange({ + row: props.row, + checked, + isShiftClick + }); + } + }); +} +function SelectGroupFormatter(props) { + const [isRowSelected, onRowSelectionChange] = useRowSelection(); + return /*#__PURE__*/jsxRuntime.jsx(SelectCellFormatter, { + "aria-label": "Select Group", + isCellSelected: props.isCellSelected, + value: isRowSelected, + onChange: checked => { + onRowSelectionChange({ + row: props.row, + checked, + isShiftClick: false + }); + } + }); +} + +const SelectColumn = { + key: SELECT_COLUMN_KEY, + name: '', + width: 35, + minWidth: 35, + maxWidth: 35, + resizable: false, + sortable: false, + frozen: true, + headerRenderer(props) { + return /*#__PURE__*/jsxRuntime.jsx(SelectCellFormatter, { + "aria-label": "Select All", + isCellSelected: props.isCellSelected, + value: props.allRowsSelected, + onChange: props.onAllRowsSelectionChange + }); + }, + formatter(props) { + return /*#__PURE__*/jsxRuntime.jsx(SelectFormatter, { + ...props + }); + }, + groupFormatter(props) { + return /*#__PURE__*/jsxRuntime.jsx(SelectGroupFormatter, { + ...props + }); + } +}; + +function getColSpan(column, lastFrozenColumnIndex, args) { + const colSpan = typeof column.colSpan === 'function' ? column.colSpan(args) : 1; + if (Number.isInteger(colSpan) && colSpan > 1 && ( + !column.frozen || column.idx + colSpan - 1 <= lastFrozenColumnIndex)) { + return colSpan; + } + return undefined; +} + +function scrollIntoView(element) { + element?.scrollIntoView({ + inline: 'nearest', + block: 'nearest' + }); +} + +const nonInputKeys = new Set([ +'Unidentified', +'Alt', 'AltGraph', 'CapsLock', 'Control', 'Fn', 'FnLock', 'Meta', 'NumLock', 'ScrollLock', 'Shift', +'Tab', +'ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'End', 'Home', 'PageDown', 'PageUp', +'Insert', +'ContextMenu', 'Escape', 'Pause', 'Play', +'PrintScreen', +'F1', +'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12']); +function isCtrlKeyHeldDown(e) { + return (e.ctrlKey || e.metaKey) && e.key !== 'Control'; +} +function isDefaultCellInput(event) { + return !nonInputKeys.has(event.key); +} + +function onEditorNavigation({ + key, + target +}) { + if (key === 'Tab' && (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement)) { + return target.matches('.rdg-editor-container > :only-child, .rdg-editor-container > label:only-child > :only-child'); + } + return false; +} + +const measuringCellClassname = "mlln6zg7-0-0-beta-19"; +function renderMeasuringCells(viewportColumns) { + return /*#__PURE__*/jsxRuntime.jsx(jsxRuntime.Fragment, { + children: viewportColumns.map(({ + key, + idx, + minWidth, + maxWidth + }) => /*#__PURE__*/jsxRuntime.jsx("div", { + className: measuringCellClassname, + style: { + gridColumnStart: idx + 1, + minWidth, + maxWidth + }, + "data-measuring-cell-key": key + }, key)) + }); +} + +function isSelectedCellEditable({ + selectedPosition, + columns, + rows, + isGroupRow +}) { + const column = columns[selectedPosition.idx]; + const row = rows[selectedPosition.rowIdx]; + return !isGroupRow(row) && isCellEditable(column, row); +} +function isCellEditable(column, row) { + return column.editor != null && !column.rowGroup && (typeof column.editable === 'function' ? column.editable(row) : column.editable) !== false; +} +function getSelectedCellColSpan({ + rows, + topSummaryRows, + bottomSummaryRows, + rowIdx, + lastFrozenColumnIndex, + column, + isGroupRow +}) { + const topSummaryRowsCount = topSummaryRows?.length ?? 0; + const minRowIdx = -1 - topSummaryRowsCount; + if (rowIdx === minRowIdx) { + return getColSpan(column, lastFrozenColumnIndex, { + type: 'HEADER' + }); + } + if (topSummaryRows && rowIdx > minRowIdx && rowIdx <= topSummaryRowsCount + minRowIdx) { + return getColSpan(column, lastFrozenColumnIndex, { + type: 'SUMMARY', + row: topSummaryRows[rowIdx + topSummaryRowsCount] + }); + } + if (rowIdx >= 0 && rowIdx < rows.length) { + const row = rows[rowIdx]; + if (!isGroupRow(row)) { + return getColSpan(column, lastFrozenColumnIndex, { + type: 'ROW', + row + }); + } + return undefined; + } + if (bottomSummaryRows) { + return getColSpan(column, lastFrozenColumnIndex, { + type: 'SUMMARY', + row: bottomSummaryRows[rowIdx - rows.length] + }); + } + return undefined; +} +function getNextSelectedCellPosition({ + cellNavigationMode, + columns, + colSpanColumns, + rows, + topSummaryRows, + bottomSummaryRows, + minRowIdx, + maxRowIdx, + currentPosition: { + idx: currentIdx + }, + nextPosition, + lastFrozenColumnIndex, + isCellWithinBounds, + isGroupRow +}) { + let { + idx: nextIdx, + rowIdx: nextRowIdx + } = nextPosition; + const setColSpan = moveRight => { + if (nextRowIdx >= 0 && nextRowIdx < rows.length) { + const row = rows[nextRowIdx]; + if (isGroupRow(row)) return; + } + for (const column of colSpanColumns) { + const colIdx = column.idx; + if (colIdx > nextIdx) break; + const colSpan = getSelectedCellColSpan({ + rows, + topSummaryRows, + bottomSummaryRows, + rowIdx: nextRowIdx, + lastFrozenColumnIndex, + column, + isGroupRow + }); + if (colSpan && nextIdx > colIdx && nextIdx < colSpan + colIdx) { + nextIdx = colIdx + (moveRight ? colSpan : 0); + break; + } + } + }; + if (isCellWithinBounds(nextPosition)) { + setColSpan(nextIdx - currentIdx > 0); + } + if (cellNavigationMode !== 'NONE') { + const columnsCount = columns.length; + const isAfterLastColumn = nextIdx === columnsCount; + const isBeforeFirstColumn = nextIdx === -1; + if (isAfterLastColumn) { + if (cellNavigationMode === 'CHANGE_ROW') { + const isLastRow = nextRowIdx === maxRowIdx; + if (!isLastRow) { + nextIdx = 0; + nextRowIdx += 1; + } + } else { + nextIdx = 0; + } + } else if (isBeforeFirstColumn) { + if (cellNavigationMode === 'CHANGE_ROW') { + const isFirstRow = nextRowIdx === minRowIdx; + if (!isFirstRow) { + nextRowIdx -= 1; + nextIdx = columnsCount - 1; + } + } else { + nextIdx = columnsCount - 1; + } + setColSpan(false); + } + } + return { + idx: nextIdx, + rowIdx: nextRowIdx + }; +} +function canExitGrid({ + cellNavigationMode, + maxColIdx, + minRowIdx, + maxRowIdx, + selectedPosition: { + rowIdx, + idx + }, + shiftKey +}) { + if (cellNavigationMode === 'NONE' || cellNavigationMode === 'CHANGE_ROW') { + const atLastCellInRow = idx === maxColIdx; + const atFirstCellInRow = idx === 0; + const atLastRow = rowIdx === maxRowIdx; + const atFirstRow = rowIdx === minRowIdx; + return shiftKey ? atFirstCellInRow && atFirstRow : atLastCellInRow && atLastRow; + } + return false; +} + +function getRowStyle(rowIdx, height) { + if (height !== undefined) { + return { + '--rdg-grid-row-start': rowIdx, + '--rdg-row-height': `${height}px` + }; + } + return { + '--rdg-grid-row-start': rowIdx + }; +} +function getCellStyle(column, colSpan) { + return { + gridColumnStart: column.idx + 1, + gridColumnEnd: colSpan !== undefined ? `span ${colSpan}` : undefined, + insetInlineStart: column.frozen ? `var(--rdg-frozen-left-${column.idx})` : undefined + }; +} +function getCellClassname(column, ...extraClasses) { + return clsx(cellClassname, ...extraClasses, column.frozen && cellFrozenClassname, column.isLastFrozenColumn && cellFrozenLastClassname); +} + +const { + min, + max, + round, + floor, + sign, + abs +} = Math; +function assertIsValidKeyGetter(keyGetter) { + if (typeof keyGetter !== 'function') { + throw new Error('Please specify the rowKeyGetter prop to use selection'); + } +} +function clampColumnWidth(width, { + minWidth, + maxWidth +}) { + width = max(width, minWidth); + + if (typeof maxWidth === 'number' && maxWidth >= minWidth) { + return min(width, maxWidth); + } + return width; +} + +const DEFAULT_COLUMN_WIDTH = 'auto'; +const DEFAULT_COLUMN_MIN_WIDTH = 80; +function useCalculatedColumns({ + rawColumns, + columnWidths, + viewportWidth, + scrollLeft, + defaultColumnOptions, + rawGroupBy, + enableVirtualization +}) { + const defaultWidth = defaultColumnOptions?.width ?? DEFAULT_COLUMN_WIDTH; + const defaultMinWidth = defaultColumnOptions?.minWidth ?? DEFAULT_COLUMN_MIN_WIDTH; + const defaultMaxWidth = defaultColumnOptions?.maxWidth ?? undefined; + const defaultFormatter = defaultColumnOptions?.formatter ?? valueFormatter; + const defaultSortable = defaultColumnOptions?.sortable ?? false; + const defaultResizable = defaultColumnOptions?.resizable ?? false; + const { + columns, + colSpanColumns, + lastFrozenColumnIndex, + groupBy + } = react.useMemo(() => { + const groupBy = []; + let lastFrozenColumnIndex = -1; + const columns = rawColumns.map(rawColumn => { + const rowGroup = rawGroupBy?.includes(rawColumn.key) ?? false; + const frozen = rowGroup || rawColumn.frozen || false; + const column = { + ...rawColumn, + idx: 0, + frozen, + isLastFrozenColumn: false, + rowGroup, + width: rawColumn.width ?? defaultWidth, + minWidth: rawColumn.minWidth ?? defaultMinWidth, + maxWidth: rawColumn.maxWidth ?? defaultMaxWidth, + sortable: rawColumn.sortable ?? defaultSortable, + resizable: rawColumn.resizable ?? defaultResizable, + formatter: rawColumn.formatter ?? defaultFormatter + }; + if (rowGroup) { + column.groupFormatter ?? (column.groupFormatter = toggleGroupFormatter); + } + if (frozen) { + lastFrozenColumnIndex++; + } + return column; + }); + columns.sort(({ + key: aKey, + frozen: frozenA + }, { + key: bKey, + frozen: frozenB + }) => { + if (aKey === SELECT_COLUMN_KEY) return -1; + if (bKey === SELECT_COLUMN_KEY) return 1; + + if (rawGroupBy?.includes(aKey)) { + if (rawGroupBy.includes(bKey)) { + return rawGroupBy.indexOf(aKey) - rawGroupBy.indexOf(bKey); + } + return -1; + } + if (rawGroupBy?.includes(bKey)) return 1; + + if (frozenA) { + if (frozenB) return 0; + return -1; + } + if (frozenB) return 1; + + return 0; + }); + const colSpanColumns = []; + columns.forEach((column, idx) => { + column.idx = idx; + if (column.rowGroup) { + groupBy.push(column.key); + } + if (column.colSpan != null) { + colSpanColumns.push(column); + } + }); + if (lastFrozenColumnIndex !== -1) { + columns[lastFrozenColumnIndex].isLastFrozenColumn = true; + } + return { + columns, + colSpanColumns, + lastFrozenColumnIndex, + groupBy + }; + }, [rawColumns, defaultWidth, defaultMinWidth, defaultMaxWidth, defaultFormatter, defaultResizable, defaultSortable, rawGroupBy]); + const { + templateColumns, + layoutCssVars, + totalFrozenColumnWidth, + columnMetrics + } = react.useMemo(() => { + const columnMetrics = new Map(); + let left = 0; + let totalFrozenColumnWidth = 0; + const templateColumns = []; + for (const column of columns) { + let width = columnWidths.get(column.key) ?? column.width; + if (typeof width === 'number') { + width = clampColumnWidth(width, column); + } else { + width = column.minWidth; + } + templateColumns.push(`${width}px`); + columnMetrics.set(column, { + width, + left + }); + left += width; + } + if (lastFrozenColumnIndex !== -1) { + const columnMetric = columnMetrics.get(columns[lastFrozenColumnIndex]); + totalFrozenColumnWidth = columnMetric.left + columnMetric.width; + } + const layoutCssVars = { + gridTemplateColumns: templateColumns.join(' ') + }; + for (let i = 0; i <= lastFrozenColumnIndex; i++) { + const column = columns[i]; + layoutCssVars[`--rdg-frozen-left-${column.idx}`] = `${columnMetrics.get(column).left}px`; + } + return { + templateColumns, + layoutCssVars, + totalFrozenColumnWidth, + columnMetrics + }; + }, [columnWidths, columns, lastFrozenColumnIndex]); + const [colOverscanStartIdx, colOverscanEndIdx] = react.useMemo(() => { + if (!enableVirtualization) { + return [0, columns.length - 1]; + } + const viewportLeft = scrollLeft + totalFrozenColumnWidth; + const viewportRight = scrollLeft + viewportWidth; + const lastColIdx = columns.length - 1; + const firstUnfrozenColumnIdx = min(lastFrozenColumnIndex + 1, lastColIdx); + + if (viewportLeft >= viewportRight) { + return [firstUnfrozenColumnIdx, firstUnfrozenColumnIdx]; + } + + let colVisibleStartIdx = firstUnfrozenColumnIdx; + while (colVisibleStartIdx < lastColIdx) { + const { + left, + width + } = columnMetrics.get(columns[colVisibleStartIdx]); + if (left + width > viewportLeft) { + break; + } + colVisibleStartIdx++; + } + + let colVisibleEndIdx = colVisibleStartIdx; + while (colVisibleEndIdx < lastColIdx) { + const { + left, + width + } = columnMetrics.get(columns[colVisibleEndIdx]); + if (left + width >= viewportRight) { + break; + } + colVisibleEndIdx++; + } + const colOverscanStartIdx = max(firstUnfrozenColumnIdx, colVisibleStartIdx - 1); + const colOverscanEndIdx = min(lastColIdx, colVisibleEndIdx + 1); + return [colOverscanStartIdx, colOverscanEndIdx]; + }, [columnMetrics, columns, lastFrozenColumnIndex, scrollLeft, totalFrozenColumnWidth, viewportWidth, enableVirtualization]); + return { + columns, + colSpanColumns, + colOverscanStartIdx, + colOverscanEndIdx, + templateColumns, + layoutCssVars, + columnMetrics, + lastFrozenColumnIndex, + totalFrozenColumnWidth, + groupBy + }; +} + +function useGridDimensions() { + const gridRef = react.useRef(null); + const [inlineSize, setInlineSize] = react.useState(1); + const [blockSize, setBlockSize] = react.useState(1); + const [isWidthInitialized, setWidthInitialized] = react.useState(false); + useLayoutEffect(() => { + const { + ResizeObserver + } = window; + + if (ResizeObserver == null) return; + const { + clientWidth, + clientHeight, + offsetWidth, + offsetHeight + } = gridRef.current; + const { + width, + height + } = gridRef.current.getBoundingClientRect(); + const initialWidth = width - offsetWidth + clientWidth; + const initialHeight = height - offsetHeight + clientHeight; + setInlineSize(initialWidth); + setBlockSize(initialHeight); + setWidthInitialized(true); + const resizeObserver = new ResizeObserver(entries => { + const size = entries[0].contentBoxSize[0]; + setInlineSize(size.inlineSize); + setBlockSize(size.blockSize); + }); + resizeObserver.observe(gridRef.current); + return () => { + resizeObserver.disconnect(); + }; + }, []); + return [gridRef, inlineSize, blockSize, isWidthInitialized]; +} + +function useLatestFunc(fn) { + const ref = react.useRef(fn); + react.useEffect(() => { + ref.current = fn; + }); + const callbackFn = react.useCallback((...args) => { + ref.current(...args); + }, []); + + return fn ? callbackFn : fn; +} + +function useRovingCellRef(isSelected) { + const [isChildFocused, setIsChildFocused] = react.useState(false); + if (isChildFocused && !isSelected) { + setIsChildFocused(false); + } + const ref = react.useCallback(cell => { + if (cell === null) return; + scrollIntoView(cell); + if (cell.contains(document.activeElement)) return; + cell.focus({ + preventScroll: true + }); + }, []); + function onFocus(event) { + if (event.target !== event.currentTarget) { + setIsChildFocused(true); + } + } + const isFocused = isSelected && !isChildFocused; + return { + ref: isSelected ? ref : undefined, + tabIndex: isFocused ? 0 : -1, + onFocus: isSelected ? onFocus : undefined + }; +} + +function useViewportColumns({ + columns, + colSpanColumns, + rows, + topSummaryRows, + bottomSummaryRows, + colOverscanStartIdx, + colOverscanEndIdx, + lastFrozenColumnIndex, + rowOverscanStartIdx, + rowOverscanEndIdx, + columnWidths, + isGroupRow +}) { + const startIdx = react.useMemo(() => { + if (colOverscanStartIdx === 0) return 0; + let startIdx = colOverscanStartIdx; + const updateStartIdx = (colIdx, colSpan) => { + if (colSpan !== undefined && colIdx + colSpan > colOverscanStartIdx) { + startIdx = colIdx; + return true; + } + return false; + }; + for (const column of colSpanColumns) { + const colIdx = column.idx; + if (colIdx >= startIdx) break; + if (updateStartIdx(colIdx, getColSpan(column, lastFrozenColumnIndex, { + type: 'HEADER' + }))) { + break; + } + + for (let rowIdx = rowOverscanStartIdx; rowIdx <= rowOverscanEndIdx; rowIdx++) { + const row = rows[rowIdx]; + if (isGroupRow(row)) continue; + if (updateStartIdx(colIdx, getColSpan(column, lastFrozenColumnIndex, { + type: 'ROW', + row + }))) { + break; + } + } + + if (topSummaryRows != null) { + for (const row of topSummaryRows) { + if (updateStartIdx(colIdx, getColSpan(column, lastFrozenColumnIndex, { + type: 'SUMMARY', + row + }))) { + break; + } + } + } + if (bottomSummaryRows != null) { + for (const row of bottomSummaryRows) { + if (updateStartIdx(colIdx, getColSpan(column, lastFrozenColumnIndex, { + type: 'SUMMARY', + row + }))) { + break; + } + } + } + } + return startIdx; + }, [rowOverscanStartIdx, rowOverscanEndIdx, rows, topSummaryRows, bottomSummaryRows, colOverscanStartIdx, lastFrozenColumnIndex, colSpanColumns, isGroupRow]); + const { + viewportColumns, + flexWidthViewportColumns + } = react.useMemo(() => { + const viewportColumns = []; + const flexWidthViewportColumns = []; + for (let colIdx = 0; colIdx <= colOverscanEndIdx; colIdx++) { + const column = columns[colIdx]; + if (colIdx < startIdx && !column.frozen) continue; + viewportColumns.push(column); + if (typeof column.width === 'string') { + flexWidthViewportColumns.push(column); + } + } + return { + viewportColumns, + flexWidthViewportColumns + }; + }, [startIdx, colOverscanEndIdx, columns]); + const unsizedFlexWidthViewportColumns = react.useMemo(() => { + return flexWidthViewportColumns.filter(column => !columnWidths.has(column.key)); + }, [flexWidthViewportColumns, columnWidths]); + return { + viewportColumns, + flexWidthViewportColumns: unsizedFlexWidthViewportColumns + }; +} + +function isReadonlyArray(arr) { + return Array.isArray(arr); +} +function useViewportRows({ + rawRows, + rowHeight, + clientHeight, + scrollTop, + groupBy, + rowGrouper, + expandedGroupIds, + enableVirtualization +}) { + const [groupedRows, rowsCount] = react.useMemo(() => { + if (groupBy.length === 0 || rowGrouper == null) return [undefined, rawRows.length]; + const groupRows = (rows, [groupByKey, ...remainingGroupByKeys], startRowIndex) => { + let groupRowsCount = 0; + const groups = {}; + for (const [key, childRows] of Object.entries(rowGrouper(rows, groupByKey))) { + const [childGroups, childRowsCount] = remainingGroupByKeys.length === 0 ? [childRows, childRows.length] : groupRows(childRows, remainingGroupByKeys, startRowIndex + groupRowsCount + 1); + groups[key] = { + childRows, + childGroups, + startRowIndex: startRowIndex + groupRowsCount + }; + groupRowsCount += childRowsCount + 1; + } + + return [groups, groupRowsCount]; + }; + return groupRows(rawRows, groupBy, 0); + }, [groupBy, rowGrouper, rawRows]); + const [rows, isGroupRow] = react.useMemo(() => { + const allGroupRows = new Set(); + if (!groupedRows) return [rawRows, isGroupRow]; + const flattenedRows = []; + const expandGroup = (rows, parentId, level) => { + if (isReadonlyArray(rows)) { + flattenedRows.push(...rows); + return; + } + Object.keys(rows).forEach((groupKey, posInSet, keys) => { + const id = parentId !== undefined ? `${parentId}__${groupKey}` : groupKey; + const isExpanded = expandedGroupIds?.has(id) ?? false; + const { + childRows, + childGroups, + startRowIndex + } = rows[groupKey]; + const groupRow = { + id, + parentId, + groupKey, + isExpanded, + childRows, + level, + posInSet, + startRowIndex, + setSize: keys.length + }; + flattenedRows.push(groupRow); + allGroupRows.add(groupRow); + if (isExpanded) { + expandGroup(childGroups, id, level + 1); + } + }); + }; + expandGroup(groupedRows, undefined, 0); + return [flattenedRows, isGroupRow]; + function isGroupRow(row) { + return allGroupRows.has(row); + } + }, [expandedGroupIds, groupedRows, rawRows]); + const { + totalRowHeight, + gridTemplateRows, + getRowTop, + getRowHeight, + findRowIdx + } = react.useMemo(() => { + if (typeof rowHeight === 'number') { + return { + totalRowHeight: rowHeight * rows.length, + gridTemplateRows: ` repeat(${rows.length}, ${rowHeight}px)`, + getRowTop: rowIdx => rowIdx * rowHeight, + getRowHeight: () => rowHeight, + findRowIdx: offset => floor(offset / rowHeight) + }; + } + let totalRowHeight = 0; + let gridTemplateRows = ' '; + const rowPositions = rows.map(row => { + const currentRowHeight = isGroupRow(row) ? rowHeight({ + type: 'GROUP', + row + }) : rowHeight({ + type: 'ROW', + row + }); + const position = { + top: totalRowHeight, + height: currentRowHeight + }; + gridTemplateRows += `${currentRowHeight}px `; + totalRowHeight += currentRowHeight; + return position; + }); + const validateRowIdx = rowIdx => { + return max(0, min(rows.length - 1, rowIdx)); + }; + return { + totalRowHeight, + gridTemplateRows, + getRowTop: rowIdx => rowPositions[validateRowIdx(rowIdx)].top, + getRowHeight: rowIdx => rowPositions[validateRowIdx(rowIdx)].height, + findRowIdx(offset) { + let start = 0; + let end = rowPositions.length - 1; + while (start <= end) { + const middle = start + floor((end - start) / 2); + const currentOffset = rowPositions[middle].top; + if (currentOffset === offset) return middle; + if (currentOffset < offset) { + start = middle + 1; + } else if (currentOffset > offset) { + end = middle - 1; + } + if (start > end) return end; + } + return 0; + } + }; + }, [isGroupRow, rowHeight, rows]); + let rowOverscanStartIdx = 0; + let rowOverscanEndIdx = rows.length - 1; + if (enableVirtualization) { + const overscanThreshold = 4; + const rowVisibleStartIdx = findRowIdx(scrollTop); + const rowVisibleEndIdx = findRowIdx(scrollTop + clientHeight); + rowOverscanStartIdx = max(0, rowVisibleStartIdx - overscanThreshold); + rowOverscanEndIdx = min(rows.length - 1, rowVisibleEndIdx + overscanThreshold); + } + return { + rowOverscanStartIdx, + rowOverscanEndIdx, + rows, + rowsCount, + totalRowHeight, + gridTemplateRows, + isGroupRow, + getRowTop, + getRowHeight, + findRowIdx + }; +} + +const headerSortCell = "h1vs8cet7-0-0-beta-19"; +const headerSortCellClassname = `rdg-header-sort-cell ${headerSortCell}`; +const headerSortName = "h1b61esp7-0-0-beta-19"; +const headerSortNameClassname = `rdg-header-sort-name ${headerSortName}`; +function headerRenderer({ + column, + sortDirection, + priority, + onSort, + isCellSelected +}) { + if (!column.sortable) return /*#__PURE__*/jsxRuntime.jsx(jsxRuntime.Fragment, { + children: column.name + }); + return /*#__PURE__*/jsxRuntime.jsx(SortableHeaderCell, { + onSort: onSort, + sortDirection: sortDirection, + priority: priority, + isCellSelected: isCellSelected, + children: column.name + }); +} +function SortableHeaderCell({ + onSort, + sortDirection, + priority, + children, + isCellSelected +}) { + const sortStatus = useDefaultComponents().sortStatus; + const { + ref, + tabIndex + } = useFocusRef(isCellSelected); + function handleKeyDown(event) { + if (event.key === ' ' || event.key === 'Enter') { + event.preventDefault(); + onSort(event.ctrlKey || event.metaKey); + } + } + function handleClick(event) { + onSort(event.ctrlKey || event.metaKey); + } + return /*#__PURE__*/jsxRuntime.jsxs("span", { + ref: ref, + tabIndex: tabIndex, + className: headerSortCellClassname, + onClick: handleClick, + onKeyDown: handleKeyDown, + children: [/*#__PURE__*/jsxRuntime.jsx("span", { + className: headerSortNameClassname, + children: children + }), /*#__PURE__*/jsxRuntime.jsx("span", { + children: sortStatus({ + sortDirection, + priority + }) + })] + }); +} + +const cellResizable = "c6l2wv17-0-0-beta-19"; +const cellResizableClassname = `rdg-cell-resizable ${cellResizable}`; +function HeaderCell({ + column, + colSpan, + isCellSelected, + onColumnResize, + allRowsSelected, + onAllRowsSelectionChange, + sortColumns, + onSortColumnsChange, + selectCell, + shouldFocusGrid, + direction +}) { + const isRtl = direction === 'rtl'; + const { + ref, + tabIndex, + onFocus + } = useRovingCellRef(isCellSelected); + const sortIndex = sortColumns?.findIndex(sort => sort.columnKey === column.key); + const sortColumn = sortIndex !== undefined && sortIndex > -1 ? sortColumns[sortIndex] : undefined; + const sortDirection = sortColumn?.direction; + const priority = sortColumn !== undefined && sortColumns.length > 1 ? sortIndex + 1 : undefined; + const ariaSort = sortDirection && !priority ? sortDirection === 'ASC' ? 'ascending' : 'descending' : undefined; + const className = getCellClassname(column, column.headerCellClass, column.resizable && cellResizableClassname); + const headerRenderer$1 = column.headerRenderer ?? headerRenderer; + function onPointerDown(event) { + if (event.pointerType === 'mouse' && event.buttons !== 1) { + return; + } + const { + currentTarget, + pointerId + } = event; + const { + right, + left + } = currentTarget.getBoundingClientRect(); + const offset = isRtl ? event.clientX - left : right - event.clientX; + if (offset > 11) { + return; + } + function onPointerMove(event) { + event.preventDefault(); + const { + right, + left + } = currentTarget.getBoundingClientRect(); + const width = isRtl ? right + offset - event.clientX : event.clientX + offset - left; + if (width > 0) { + onColumnResize(column, width); + } + } + function onLostPointerCapture() { + currentTarget.removeEventListener('pointermove', onPointerMove); + currentTarget.removeEventListener('lostpointercapture', onLostPointerCapture); + } + currentTarget.setPointerCapture(pointerId); + currentTarget.addEventListener('pointermove', onPointerMove); + currentTarget.addEventListener('lostpointercapture', onLostPointerCapture); + } + function onSort(ctrlClick) { + if (onSortColumnsChange == null) return; + const { + sortDescendingFirst + } = column; + if (sortColumn === undefined) { + const nextSort = { + columnKey: column.key, + direction: sortDescendingFirst ? 'DESC' : 'ASC' + }; + onSortColumnsChange(sortColumns && ctrlClick ? [...sortColumns, nextSort] : [nextSort]); + } else { + let nextSortColumn; + if (sortDescendingFirst === true && sortDirection === 'DESC' || sortDescendingFirst !== true && sortDirection === 'ASC') { + nextSortColumn = { + columnKey: column.key, + direction: sortDirection === 'ASC' ? 'DESC' : 'ASC' + }; + } + if (ctrlClick) { + const nextSortColumns = [...sortColumns]; + if (nextSortColumn) { + nextSortColumns[sortIndex] = nextSortColumn; + } else { + nextSortColumns.splice(sortIndex, 1); + } + onSortColumnsChange(nextSortColumns); + } else { + onSortColumnsChange(nextSortColumn ? [nextSortColumn] : []); + } + } + } + function onClick() { + selectCell(column.idx); + } + function onDoubleClick(event) { + const { + right, + left + } = event.currentTarget.getBoundingClientRect(); + const offset = isRtl ? event.clientX - left : right - event.clientX; + if (offset > 11) { + return; + } + onColumnResize(column, 'max-content'); + } + function handleFocus(event) { + onFocus?.(event); + if (shouldFocusGrid) { + selectCell(0); + } + } + return /*#__PURE__*/jsxRuntime.jsx("div", { + role: "columnheader", + "aria-colindex": column.idx + 1, + "aria-selected": isCellSelected, + "aria-sort": ariaSort, + "aria-colspan": colSpan, + ref: ref + , + tabIndex: shouldFocusGrid ? 0 : tabIndex, + className: className, + style: getCellStyle(column, colSpan), + onFocus: handleFocus, + onClick: onClick, + onDoubleClick: column.resizable ? onDoubleClick : undefined, + onPointerDown: column.resizable ? onPointerDown : undefined, + children: headerRenderer$1({ + column, + sortDirection, + priority, + onSort, + allRowsSelected, + onAllRowsSelectionChange, + isCellSelected + }) + }); +} + +const headerRow = "h10tskcx7-0-0-beta-19"; +const headerRowClassname = `rdg-header-row ${headerRow}`; +function HeaderRow({ + columns, + allRowsSelected, + onAllRowsSelectionChange, + onColumnResize, + sortColumns, + onSortColumnsChange, + lastFrozenColumnIndex, + selectedCellIdx, + selectCell, + shouldFocusGrid, + direction +}) { + const cells = []; + for (let index = 0; index < columns.length; index++) { + const column = columns[index]; + const colSpan = getColSpan(column, lastFrozenColumnIndex, { + type: 'HEADER' + }); + if (colSpan !== undefined) { + index += colSpan - 1; + } + cells.push( /*#__PURE__*/jsxRuntime.jsx(HeaderCell, { + column: column, + colSpan: colSpan, + isCellSelected: selectedCellIdx === column.idx, + onColumnResize: onColumnResize, + allRowsSelected: allRowsSelected, + onAllRowsSelectionChange: onAllRowsSelectionChange, + onSortColumnsChange: onSortColumnsChange, + sortColumns: sortColumns, + selectCell: selectCell, + shouldFocusGrid: shouldFocusGrid && index === 0, + direction: direction + }, column.key)); + } + return /*#__PURE__*/jsxRuntime.jsx("div", { + role: "row", + "aria-rowindex": 1, + className: clsx(headerRowClassname, selectedCellIdx === -1 && rowSelectedClassname), + style: getRowStyle(1), + children: cells + }); +} +const HeaderRow$1 = /*#__PURE__*/react.memo(HeaderRow); + +const cellCopied = "c6ra8a37-0-0-beta-19"; +const cellCopiedClassname = `rdg-cell-copied ${cellCopied}`; +const cellDraggedOver = "cq910m07-0-0-beta-19"; +const cellDraggedOverClassname = `rdg-cell-dragged-over ${cellDraggedOver}`; +function Cell({ + column, + colSpan, + isCellSelected, + isCopied, + isDraggedOver, + row, + dragHandle, + onRowClick, + onRowDoubleClick, + onRowChange, + selectCell, + ...props +}) { + const { + ref, + tabIndex, + onFocus + } = useRovingCellRef(isCellSelected); + const { + cellClass + } = column; + const className = getCellClassname(column, typeof cellClass === 'function' ? cellClass(row) : cellClass, isCopied && cellCopiedClassname, isDraggedOver && cellDraggedOverClassname); + function selectCellWrapper(openEditor) { + selectCell(row, column, openEditor); + } + function handleClick() { + selectCellWrapper(column.editorOptions?.editOnClick); + onRowClick?.(row, column); + } + function handleContextMenu() { + selectCellWrapper(); + } + function handleDoubleClick() { + selectCellWrapper(true); + onRowDoubleClick?.(row, column); + } + function handleRowChange(newRow) { + onRowChange(column, newRow); + } + return /*#__PURE__*/jsxRuntime.jsx("div", { + role: "gridcell", + "aria-colindex": column.idx + 1, + "aria-selected": isCellSelected, + "aria-colspan": colSpan, + "aria-readonly": !isCellEditable(column, row) || undefined, + ref: ref, + tabIndex: tabIndex, + className: className, + style: getCellStyle(column, colSpan), + onClick: handleClick, + onDoubleClick: handleDoubleClick, + onContextMenu: handleContextMenu, + onFocus: onFocus, + ...props, + children: !column.rowGroup && /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, { + children: [column.formatter({ + column, + row, + isCellSelected, + onRowChange: handleRowChange + }), dragHandle] + }) + }); +} +const Cell$1 = /*#__PURE__*/react.memo(Cell); + +function Row({ + className, + rowIdx, + gridRowStart, + height, + selectedCellIdx, + isRowSelected, + copiedCellIdx, + draggedOverCellIdx, + lastFrozenColumnIndex, + row, + viewportColumns, + selectedCellEditor, + selectedCellDragHandle, + onRowClick, + onRowDoubleClick, + rowClass, + setDraggedOverRowIdx, + onMouseEnter, + onRowChange, + selectCell, + ...props +}, ref) { + const handleRowChange = useLatestFunc((column, newRow) => { + onRowChange(column, rowIdx, newRow); + }); + function handleDragEnter(event) { + setDraggedOverRowIdx?.(rowIdx); + onMouseEnter?.(event); + } + className = clsx(rowClassname, `rdg-row-${rowIdx % 2 === 0 ? 'even' : 'odd'}`, rowClass?.(row), className, selectedCellIdx === -1 && rowSelectedClassname); + const cells = []; + for (let index = 0; index < viewportColumns.length; index++) { + const column = viewportColumns[index]; + const { + idx + } = column; + const colSpan = getColSpan(column, lastFrozenColumnIndex, { + type: 'ROW', + row + }); + if (colSpan !== undefined) { + index += colSpan - 1; + } + const isCellSelected = selectedCellIdx === idx; + if (isCellSelected && selectedCellEditor) { + cells.push(selectedCellEditor); + } else { + cells.push( /*#__PURE__*/jsxRuntime.jsx(Cell$1, { + column: column, + colSpan: colSpan, + row: row, + isCopied: copiedCellIdx === idx, + isDraggedOver: draggedOverCellIdx === idx, + isCellSelected: isCellSelected, + dragHandle: isCellSelected ? selectedCellDragHandle : undefined, + onRowClick: onRowClick, + onRowDoubleClick: onRowDoubleClick, + onRowChange: handleRowChange, + selectCell: selectCell + }, column.key)); + } + } + return /*#__PURE__*/jsxRuntime.jsx(RowSelectionProvider, { + value: isRowSelected, + children: /*#__PURE__*/jsxRuntime.jsx("div", { + role: "row", + ref: ref, + className: className, + onMouseEnter: handleDragEnter, + style: getRowStyle(gridRowStart, height), + ...props, + children: cells + }) + }); +} +const RowComponent = /*#__PURE__*/react.memo( /*#__PURE__*/react.forwardRef(Row)); +const RowComponent$1 = RowComponent; +function defaultRowRenderer(key, props) { + return /*#__PURE__*/jsxRuntime.jsx(RowComponent, { + ...props + }, key); +} + +function GroupCell({ + id, + groupKey, + childRows, + isExpanded, + isCellSelected, + column, + row, + groupColumnIndex, + toggleGroup: toggleGroupWrapper +}) { + const { + ref, + tabIndex, + onFocus + } = useRovingCellRef(isCellSelected); + function toggleGroup() { + toggleGroupWrapper(id); + } + + const isLevelMatching = column.rowGroup && groupColumnIndex === column.idx; + return /*#__PURE__*/jsxRuntime.jsx("div", { + role: "gridcell", + "aria-colindex": column.idx + 1, + "aria-selected": isCellSelected, + ref: ref, + tabIndex: tabIndex, + className: getCellClassname(column), + style: { + ...getCellStyle(column), + cursor: isLevelMatching ? 'pointer' : 'default' + }, + onClick: isLevelMatching ? toggleGroup : undefined, + onFocus: onFocus, + children: (!column.rowGroup || groupColumnIndex === column.idx) && column.groupFormatter?.({ + groupKey, + childRows, + column, + row, + isExpanded, + isCellSelected, + toggleGroup + }) + }, column.key); +} +const GroupCell$1 = /*#__PURE__*/react.memo(GroupCell); + +const groupRow = "g1yxluv37-0-0-beta-19"; +const groupRowClassname = `rdg-group-row ${groupRow}`; +function GroupedRow({ + id, + groupKey, + viewportColumns, + childRows, + rowIdx, + row, + gridRowStart, + height, + level, + isExpanded, + selectedCellIdx, + isRowSelected, + selectGroup, + toggleGroup, + ...props +}) { + const idx = viewportColumns[0].key === SELECT_COLUMN_KEY ? level + 1 : level; + function handleSelectGroup() { + selectGroup(rowIdx); + } + return /*#__PURE__*/jsxRuntime.jsx(RowSelectionProvider, { + value: isRowSelected, + children: /*#__PURE__*/jsxRuntime.jsx("div", { + role: "row", + "aria-level": level, + "aria-expanded": isExpanded, + className: clsx(rowClassname, groupRowClassname, `rdg-row-${rowIdx % 2 === 0 ? 'even' : 'odd'}`, selectedCellIdx === -1 && rowSelectedClassname), + onClick: handleSelectGroup, + style: getRowStyle(gridRowStart, height), + ...props, + children: viewportColumns.map(column => /*#__PURE__*/jsxRuntime.jsx(GroupCell$1, { + id: id, + groupKey: groupKey, + childRows: childRows, + isExpanded: isExpanded, + isCellSelected: selectedCellIdx === column.idx, + column: column, + row: row, + groupColumnIndex: idx, + toggleGroup: toggleGroup + }, column.key)) + }) + }); +} +const GroupRowRenderer = /*#__PURE__*/react.memo(GroupedRow); + +const summaryCellClassname = "s8wc6fl7-0-0-beta-19"; +function SummaryCell({ + column, + colSpan, + row, + isCellSelected, + selectCell +}) { + const { + ref, + tabIndex, + onFocus + } = useRovingCellRef(isCellSelected); + const { + summaryCellClass + } = column; + const className = getCellClassname(column, summaryCellClassname, typeof summaryCellClass === 'function' ? summaryCellClass(row) : summaryCellClass); + function onClick() { + selectCell(row, column); + } + return /*#__PURE__*/jsxRuntime.jsx("div", { + role: "gridcell", + "aria-colindex": column.idx + 1, + "aria-colspan": colSpan, + "aria-selected": isCellSelected, + ref: ref, + tabIndex: tabIndex, + className: className, + style: getCellStyle(column, colSpan), + onClick: onClick, + onFocus: onFocus, + children: column.summaryFormatter?.({ + column, + row, + isCellSelected + }) + }); +} +const SummaryCell$1 = /*#__PURE__*/react.memo(SummaryCell); + +const summaryRow = "skuhp557-0-0-beta-19"; +const topSummaryRow = "tf8l5ub7-0-0-beta-19"; +const topSummaryRowBorderClassname = "tb9ughf7-0-0-beta-19"; +const bottomSummaryRowBorderClassname = "b1yssfnt7-0-0-beta-19"; +const summaryRowClassname = `rdg-summary-row ${summaryRow}`; +const topSummaryRowClassname = `rdg-top-summary-row ${topSummaryRow}`; +function SummaryRow({ + rowIdx, + gridRowStart, + row, + viewportColumns, + top, + bottom, + lastFrozenColumnIndex, + selectedCellIdx, + lastTopRowIdx, + selectCell, + 'aria-rowindex': ariaRowIndex +}) { + const cells = []; + for (let index = 0; index < viewportColumns.length; index++) { + const column = viewportColumns[index]; + const colSpan = getColSpan(column, lastFrozenColumnIndex, { + type: 'SUMMARY', + row + }); + if (colSpan !== undefined) { + index += colSpan - 1; + } + const isCellSelected = selectedCellIdx === column.idx; + cells.push( /*#__PURE__*/jsxRuntime.jsx(SummaryCell$1, { + column: column, + colSpan: colSpan, + row: row, + isCellSelected: isCellSelected, + selectCell: selectCell + }, column.key)); + } + const isTop = lastTopRowIdx !== undefined; + return /*#__PURE__*/jsxRuntime.jsx("div", { + role: "row", + "aria-rowindex": ariaRowIndex, + className: clsx(rowClassname, `rdg-row-${rowIdx % 2 === 0 ? 'even' : 'odd'}`, summaryRowClassname, isTop ? [topSummaryRowClassname, lastTopRowIdx === rowIdx && topSummaryRowBorderClassname] : ['rdg-bottom-summary-row', rowIdx === 0 && bottomSummaryRowBorderClassname], selectedCellIdx === -1 && rowSelectedClassname), + style: { + ...getRowStyle(gridRowStart), + '--rdg-summary-row-top': top !== undefined ? `${top}px` : undefined, + '--rdg-summary-row-bottom': bottom !== undefined ? `${bottom}px` : undefined + }, + children: cells + }); +} +const SummaryRow$1 = /*#__PURE__*/react.memo(SummaryRow); + +const cellEditing = "cis5rrm7-0-0-beta-19"; +function EditCell({ + column, + colSpan, + row, + onRowChange, + closeEditor +}) { + const frameRequestRef = react.useRef(); + const commitOnOutsideClick = column.editorOptions?.commitOnOutsideClick !== false; + + const commitOnOutsideMouseDown = useLatestFunc(() => { + onClose(true); + }); + react.useEffect(() => { + if (!commitOnOutsideClick) return; + function onWindowCaptureMouseDown() { + frameRequestRef.current = requestAnimationFrame(commitOnOutsideMouseDown); + } + addEventListener('mousedown', onWindowCaptureMouseDown, { + capture: true + }); + return () => { + removeEventListener('mousedown', onWindowCaptureMouseDown, { + capture: true + }); + cancelFrameRequest(); + }; + }, [commitOnOutsideClick, commitOnOutsideMouseDown]); + function cancelFrameRequest() { + cancelAnimationFrame(frameRequestRef.current); + } + function onKeyDown(event) { + if (event.key === 'Escape') { + event.stopPropagation(); + onClose(); + } else if (event.key === 'Enter') { + event.stopPropagation(); + onClose(true); + } else { + const onNavigation = column.editorOptions?.onNavigation ?? onEditorNavigation; + if (!onNavigation(event)) { + event.stopPropagation(); + } + } + } + function onClose(commitChanges) { + if (commitChanges) { + onRowChange(row, true); + } else { + closeEditor(); + } + } + const { + cellClass + } = column; + const className = getCellClassname(column, 'rdg-editor-container', typeof cellClass === 'function' ? cellClass(row) : cellClass, !column.editorOptions?.renderFormatter && cellEditing); + return /*#__PURE__*/jsxRuntime.jsx("div", { + role: "gridcell", + "aria-colindex": column.idx + 1, + "aria-colspan": colSpan, + "aria-selected": true, + className: className, + style: getCellStyle(column, colSpan), + onKeyDown: onKeyDown, + onMouseDownCapture: commitOnOutsideClick ? cancelFrameRequest : undefined, + children: column.editor != null && /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, { + children: [column.editor({ + column, + row, + onRowChange, + onClose + }), column.editorOptions?.renderFormatter && column.formatter({ + column, + row, + isCellSelected: true, + onRowChange + })] + }) + }); +} + +const cellDragHandle = "c1w9bbhr7-0-0-beta-19"; +const cellDragHandleClassname = `rdg-cell-drag-handle ${cellDragHandle}`; +function DragHandle({ + rows, + columns, + selectedPosition, + latestDraggedOverRowIdx, + isCellEditable, + onRowsChange, + onFill, + setDragging, + setDraggedOverRowIdx +}) { + function handleMouseDown(event) { + if (event.buttons !== 1) return; + setDragging(true); + window.addEventListener('mouseover', onMouseOver); + window.addEventListener('mouseup', onMouseUp); + function onMouseOver(event) { + if (event.buttons !== 1) onMouseUp(); + } + function onMouseUp() { + window.removeEventListener('mouseover', onMouseOver); + window.removeEventListener('mouseup', onMouseUp); + setDragging(false); + handleDragEnd(); + } + } + function handleDragEnd() { + const overRowIdx = latestDraggedOverRowIdx.current; + if (overRowIdx === undefined) return; + const { + rowIdx + } = selectedPosition; + const startRowIndex = rowIdx < overRowIdx ? rowIdx + 1 : overRowIdx; + const endRowIndex = rowIdx < overRowIdx ? overRowIdx + 1 : rowIdx; + updateRows(startRowIndex, endRowIndex); + setDraggedOverRowIdx(undefined); + } + function handleDoubleClick(event) { + event.stopPropagation(); + updateRows(selectedPosition.rowIdx + 1, rows.length); + } + function updateRows(startRowIdx, endRowIdx) { + const { + idx, + rowIdx + } = selectedPosition; + const column = columns[idx]; + const sourceRow = rows[rowIdx]; + const updatedRows = [...rows]; + const indexes = []; + for (let i = startRowIdx; i < endRowIdx; i++) { + if (isCellEditable({ + rowIdx: i, + idx + })) { + const updatedRow = onFill({ + columnKey: column.key, + sourceRow, + targetRow: rows[i] + }); + if (updatedRow !== rows[i]) { + updatedRows[i] = updatedRow; + indexes.push(i); + } + } + } + if (indexes.length > 0) { + onRowsChange?.(updatedRows, { + indexes, + column + }); + } + } + return /*#__PURE__*/jsxRuntime.jsx("div", { + className: cellDragHandleClassname, + onMouseDown: handleMouseDown, + onDoubleClick: handleDoubleClick + }); +} + +const arrow = "a3ejtar7-0-0-beta-19"; +const arrowClassname = `rdg-sort-arrow ${arrow}`; +function sortStatus({ + sortDirection, + priority +}) { + return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, { + children: [sortIcon({ + sortDirection + }), sortPriority({ + priority + })] + }); +} +function sortIcon({ + sortDirection +}) { + if (sortDirection === undefined) return null; + return /*#__PURE__*/jsxRuntime.jsx("svg", { + viewBox: "0 0 12 8", + width: "12", + height: "8", + className: arrowClassname, + "aria-hidden": true, + children: /*#__PURE__*/jsxRuntime.jsx("path", { + d: sortDirection === 'ASC' ? 'M0 8 6 0 12 8' : 'M0 0 6 8 12 0' + }) + }); +} +function sortPriority({ + priority +}) { + return priority; +} + +const initialPosition = { + idx: -1, + rowIdx: -2, + mode: 'SELECT' +}; +function DataGrid(props, ref) { + const { + columns: rawColumns, + rows: rawRows, + topSummaryRows, + bottomSummaryRows, + rowKeyGetter, + onRowsChange, + rowHeight: rawRowHeight, + headerRowHeight: rawHeaderRowHeight, + summaryRowHeight: rawSummaryRowHeight, + selectedRows, + onSelectedRowsChange, + sortColumns, + onSortColumnsChange, + defaultColumnOptions, + groupBy: rawGroupBy, + rowGrouper, + expandedGroupIds, + onExpandedGroupIdsChange, + onRowClick, + onRowDoubleClick, + onScroll, + onColumnResize, + onSelectedCellChange, + onFill, + onCopy, + onPaste, + cellNavigationMode: rawCellNavigationMode, + enableVirtualization: rawEnableVirtualization, + shouldCloseEditor, + renderers, + className, + style, + rowClass, + direction: rawDirection, + 'aria-label': ariaLabel, + 'aria-labelledby': ariaLabelledBy, + 'aria-describedby': ariaDescribedBy, + 'data-testid': testId + } = props; + + const defaultComponents = useDefaultComponents(); + const rowHeight = rawRowHeight ?? 35; + const headerRowHeight = rawHeaderRowHeight ?? (typeof rowHeight === 'number' ? rowHeight : 35); + const summaryRowHeight = rawSummaryRowHeight ?? (typeof rowHeight === 'number' ? rowHeight : 35); + const rowRenderer = renderers?.rowRenderer ?? defaultComponents?.rowRenderer ?? defaultRowRenderer; + const sortStatus$1 = renderers?.sortStatus ?? defaultComponents?.sortStatus ?? sortStatus; + const checkboxFormatter$1 = renderers?.checkboxFormatter ?? defaultComponents?.checkboxFormatter ?? checkboxFormatter; + const noRowsFallback = renderers?.noRowsFallback ?? defaultComponents?.noRowsFallback; + const cellNavigationMode = rawCellNavigationMode ?? 'NONE'; + const enableVirtualization = rawEnableVirtualization ?? true; + const direction = rawDirection ?? 'ltr'; + + const [scrollTop, setScrollTop] = react.useState(0); + const [scrollLeft, setScrollLeft] = react.useState(0); + const [columnWidths, setColumnWidths] = react.useState(() => new Map()); + const [selectedPosition, setSelectedPosition] = react.useState(initialPosition); + const [copiedCell, setCopiedCell] = react.useState(null); + const [isDragging, setDragging] = react.useState(false); + const [draggedOverRowIdx, setOverRowIdx] = react.useState(undefined); + + const prevSelectedPosition = react.useRef(selectedPosition); + const latestDraggedOverRowIdx = react.useRef(draggedOverRowIdx); + const lastSelectedRowIdx = react.useRef(-1); + const rowRef = react.useRef(null); + + const [gridRef, gridWidth, gridHeight, isWidthInitialized] = useGridDimensions(); + const headerRowsCount = 1; + const topSummaryRowsCount = topSummaryRows?.length ?? 0; + const bottomSummaryRowsCount = bottomSummaryRows?.length ?? 0; + const summaryRowsCount = topSummaryRowsCount + bottomSummaryRowsCount; + const clientHeight = gridHeight - headerRowHeight - summaryRowsCount * summaryRowHeight; + const isSelectable = selectedRows != null && onSelectedRowsChange != null; + const isRtl = direction === 'rtl'; + const leftKey = isRtl ? 'ArrowRight' : 'ArrowLeft'; + const rightKey = isRtl ? 'ArrowLeft' : 'ArrowRight'; + const defaultGridComponents = react.useMemo(() => ({ + sortStatus: sortStatus$1, + checkboxFormatter: checkboxFormatter$1 + }), [sortStatus$1, checkboxFormatter$1]); + const allRowsSelected = react.useMemo(() => { + const { + length + } = rawRows; + return length !== 0 && selectedRows != null && rowKeyGetter != null && selectedRows.size >= length && rawRows.every(row => selectedRows.has(rowKeyGetter(row))); + }, [rawRows, selectedRows, rowKeyGetter]); + const { + columns, + colSpanColumns, + colOverscanStartIdx, + colOverscanEndIdx, + templateColumns, + layoutCssVars, + columnMetrics, + lastFrozenColumnIndex, + totalFrozenColumnWidth, + groupBy + } = useCalculatedColumns({ + rawColumns, + columnWidths, + scrollLeft, + viewportWidth: gridWidth, + defaultColumnOptions, + rawGroupBy: rowGrouper ? rawGroupBy : undefined, + enableVirtualization + }); + const { + rowOverscanStartIdx, + rowOverscanEndIdx, + rows, + rowsCount, + totalRowHeight, + gridTemplateRows, + isGroupRow, + getRowTop, + getRowHeight, + findRowIdx + } = useViewportRows({ + rawRows, + groupBy, + rowGrouper, + rowHeight, + clientHeight, + scrollTop, + expandedGroupIds, + enableVirtualization + }); + const { + viewportColumns, + flexWidthViewportColumns + } = useViewportColumns({ + columns, + colSpanColumns, + colOverscanStartIdx, + colOverscanEndIdx, + lastFrozenColumnIndex, + rowOverscanStartIdx, + rowOverscanEndIdx, + rows, + topSummaryRows, + bottomSummaryRows, + columnWidths, + isGroupRow + }); + const hasGroups = groupBy.length > 0 && typeof rowGrouper === 'function'; + const minColIdx = hasGroups ? -1 : 0; + const maxColIdx = columns.length - 1; + const minRowIdx = -1 - topSummaryRowsCount; + const maxRowIdx = rows.length + bottomSummaryRowsCount - 1; + const selectedCellIsWithinSelectionBounds = isCellWithinSelectionBounds(selectedPosition); + const selectedCellIsWithinViewportBounds = isCellWithinViewportBounds(selectedPosition); + + const handleColumnResizeLatest = useLatestFunc(handleColumnResize); + const onSortColumnsChangeLatest = useLatestFunc(onSortColumnsChange); + const onRowClickLatest = useLatestFunc(onRowClick); + const onRowDoubleClickLatest = useLatestFunc(onRowDoubleClick); + const selectRowLatest = useLatestFunc(selectRow); + const selectAllRowsLatest = useLatestFunc(selectAllRows); + const handleFormatterRowChangeLatest = useLatestFunc(updateRow); + const selectViewportCellLatest = useLatestFunc((row, column, enableEditor) => { + const rowIdx = rows.indexOf(row); + selectCell({ + rowIdx, + idx: column.idx + }, enableEditor); + }); + const selectGroupLatest = useLatestFunc(rowIdx => { + selectCell({ + rowIdx, + idx: -1 + }); + }); + const selectHeaderCellLatest = useLatestFunc(idx => { + selectCell({ + rowIdx: minRowIdx, + idx + }); + }); + const selectTopSummaryCellLatest = useLatestFunc((summaryRow, column) => { + const rowIdx = topSummaryRows.indexOf(summaryRow); + selectCell({ + rowIdx: rowIdx + minRowIdx + 1, + idx: column.idx + }); + }); + const selectBottomSummaryCellLatest = useLatestFunc((summaryRow, column) => { + const rowIdx = bottomSummaryRows.indexOf(summaryRow) + rows.length; + selectCell({ + rowIdx, + idx: column.idx + }); + }); + const toggleGroupLatest = useLatestFunc(toggleGroup); + + useLayoutEffect(() => { + if (!selectedCellIsWithinSelectionBounds || isSamePosition(selectedPosition, prevSelectedPosition.current)) { + prevSelectedPosition.current = selectedPosition; + return; + } + prevSelectedPosition.current = selectedPosition; + if (selectedPosition.idx === -1) { + rowRef.current.focus({ + preventScroll: true + }); + scrollIntoView(rowRef.current); + } + }); + useLayoutEffect(() => { + if (!isWidthInitialized || flexWidthViewportColumns.length === 0) return; + setColumnWidths(columnWidths => { + const newColumnWidths = new Map(columnWidths); + const grid = gridRef.current; + for (const column of flexWidthViewportColumns) { + const measuringCell = grid.querySelector(`[data-measuring-cell-key="${column.key}"]`); + const { + width + } = measuringCell.getBoundingClientRect(); + newColumnWidths.set(column.key, width); + } + return newColumnWidths; + }); + }, [isWidthInitialized, flexWidthViewportColumns, gridRef]); + react.useImperativeHandle(ref, () => ({ + element: gridRef.current, + scrollToColumn, + scrollToRow(rowIdx) { + const { + current + } = gridRef; + if (!current) return; + current.scrollTo({ + top: getRowTop(rowIdx), + behavior: 'smooth' + }); + }, + selectCell + })); + + const setDraggedOverRowIdx = react.useCallback(rowIdx => { + setOverRowIdx(rowIdx); + latestDraggedOverRowIdx.current = rowIdx; + }, []); + + function handleColumnResize(column, width) { + const { + style + } = gridRef.current; + const newTemplateColumns = [...templateColumns]; + newTemplateColumns[column.idx] = width === 'max-content' ? width : `${width}px`; + style.gridTemplateColumns = newTemplateColumns.join(' '); + const measuringCell = gridRef.current.querySelector(`[data-measuring-cell-key="${column.key}"]`); + const measuredWidth = measuringCell.getBoundingClientRect().width; + const measuredWidthPx = `${measuredWidth}px`; + + if (newTemplateColumns[column.idx] !== measuredWidthPx) { + newTemplateColumns[column.idx] = measuredWidthPx; + style.gridTemplateColumns = newTemplateColumns.join(' '); + } + if (columnWidths.get(column.key) === measuredWidth) return; + const newColumnWidths = new Map(columnWidths); + newColumnWidths.set(column.key, measuredWidth); + setColumnWidths(newColumnWidths); + onColumnResize?.(column.idx, measuredWidth); + } + function selectRow({ + row, + checked, + isShiftClick + }) { + if (!onSelectedRowsChange) return; + assertIsValidKeyGetter(rowKeyGetter); + const newSelectedRows = new Set(selectedRows); + if (isGroupRow(row)) { + for (const childRow of row.childRows) { + const rowKey = rowKeyGetter(childRow); + if (checked) { + newSelectedRows.add(rowKey); + } else { + newSelectedRows.delete(rowKey); + } + } + onSelectedRowsChange(newSelectedRows); + return; + } + const rowKey = rowKeyGetter(row); + if (checked) { + newSelectedRows.add(rowKey); + const previousRowIdx = lastSelectedRowIdx.current; + const rowIdx = rows.indexOf(row); + lastSelectedRowIdx.current = rowIdx; + if (isShiftClick && previousRowIdx !== -1 && previousRowIdx !== rowIdx) { + const step = sign(rowIdx - previousRowIdx); + for (let i = previousRowIdx + step; i !== rowIdx; i += step) { + const row = rows[i]; + if (isGroupRow(row)) continue; + newSelectedRows.add(rowKeyGetter(row)); + } + } + } else { + newSelectedRows.delete(rowKey); + lastSelectedRowIdx.current = -1; + } + onSelectedRowsChange(newSelectedRows); + } + function selectAllRows(checked) { + if (!onSelectedRowsChange) return; + assertIsValidKeyGetter(rowKeyGetter); + const newSelectedRows = new Set(selectedRows); + for (const row of rawRows) { + const rowKey = rowKeyGetter(row); + if (checked) { + newSelectedRows.add(rowKey); + } else { + newSelectedRows.delete(rowKey); + } + } + onSelectedRowsChange(newSelectedRows); + } + function toggleGroup(expandedGroupId) { + if (!onExpandedGroupIdsChange) return; + const newExpandedGroupIds = new Set(expandedGroupIds); + if (newExpandedGroupIds.has(expandedGroupId)) { + newExpandedGroupIds.delete(expandedGroupId); + } else { + newExpandedGroupIds.add(expandedGroupId); + } + onExpandedGroupIdsChange(newExpandedGroupIds); + } + function handleKeyDown(event) { + if (!(event.target instanceof Element)) return; + const isCellEvent = event.target.closest('.rdg-cell') !== null; + const isRowEvent = hasGroups && event.target === rowRef.current; + if (!isCellEvent && !isRowEvent) return; + const { + key, + keyCode + } = event; + const { + rowIdx + } = selectedPosition; + if (selectedCellIsWithinViewportBounds && (onPaste != null || onCopy != null) && isCtrlKeyHeldDown(event) && !isGroupRow(rows[rowIdx]) && selectedPosition.mode === 'SELECT') { + const cKey = 67; + const vKey = 86; + if (keyCode === cKey) { + handleCopy(); + return; + } + if (keyCode === vKey) { + handlePaste(); + return; + } + } + if (isRowIdxWithinViewportBounds(rowIdx)) { + const row = rows[rowIdx]; + if (isGroupRow(row) && selectedPosition.idx === -1 && ( + key === leftKey && row.isExpanded || + key === rightKey && !row.isExpanded)) { + event.preventDefault(); + toggleGroup(row.id); + return; + } + } + switch (event.key) { + case 'Escape': + setCopiedCell(null); + return; + case 'ArrowUp': + case 'ArrowDown': + case 'ArrowLeft': + case 'ArrowRight': + case 'Tab': + case 'Home': + case 'End': + case 'PageUp': + case 'PageDown': + navigate(event); + break; + default: + handleCellInput(event); + break; + } + } + function handleScroll(event) { + const { + scrollTop, + scrollLeft + } = event.currentTarget; + reactDom.flushSync(() => { + setScrollTop(scrollTop); + setScrollLeft(abs(scrollLeft)); + }); + onScroll?.(event); + } + function getRawRowIdx(rowIdx) { + return hasGroups ? rawRows.indexOf(rows[rowIdx]) : rowIdx; + } + function updateRow(column, rowIdx, row) { + if (typeof onRowsChange !== 'function') return; + const rawRowIdx = getRawRowIdx(rowIdx); + if (row === rawRows[rawRowIdx]) return; + const updatedRows = [...rawRows]; + updatedRows[rawRowIdx] = row; + onRowsChange(updatedRows, { + indexes: [rawRowIdx], + column + }); + } + function commitEditorChanges() { + if (selectedPosition.mode !== 'EDIT') return; + updateRow(columns[selectedPosition.idx], selectedPosition.rowIdx, selectedPosition.row); + } + function handleCopy() { + const { + idx, + rowIdx + } = selectedPosition; + const sourceRow = rawRows[getRawRowIdx(rowIdx)]; + const sourceColumnKey = columns[idx].key; + setCopiedCell({ + row: sourceRow, + columnKey: sourceColumnKey + }); + onCopy?.({ + sourceRow, + sourceColumnKey + }); + } + function handlePaste() { + if (!onPaste || !onRowsChange || copiedCell === null || !isCellEditable(selectedPosition)) { + return; + } + const { + idx, + rowIdx + } = selectedPosition; + const targetColumn = columns[idx]; + const targetRow = rawRows[getRawRowIdx(rowIdx)]; + const updatedTargetRow = onPaste({ + sourceRow: copiedCell.row, + sourceColumnKey: copiedCell.columnKey, + targetRow, + targetColumnKey: targetColumn.key + }); + updateRow(targetColumn, rowIdx, updatedTargetRow); + } + function handleCellInput(event) { + if (!selectedCellIsWithinViewportBounds) return; + const row = rows[selectedPosition.rowIdx]; + if (isGroupRow(row)) return; + const { + key, + shiftKey + } = event; + + if (isSelectable && shiftKey && key === ' ') { + assertIsValidKeyGetter(rowKeyGetter); + const rowKey = rowKeyGetter(row); + selectRow({ + row, + checked: !selectedRows.has(rowKey), + isShiftClick: false + }); + event.preventDefault(); + return; + } + const column = columns[selectedPosition.idx]; + column.editorOptions?.onCellKeyDown?.(event); + if (event.isDefaultPrevented()) return; + if (isCellEditable(selectedPosition) && isDefaultCellInput(event)) { + setSelectedPosition(({ + idx, + rowIdx + }) => ({ + idx, + rowIdx, + mode: 'EDIT', + row, + originalRow: row + })); + } + } + + function isColIdxWithinSelectionBounds(idx) { + return idx >= minColIdx && idx <= maxColIdx; + } + function isRowIdxWithinViewportBounds(rowIdx) { + return rowIdx >= 0 && rowIdx < rows.length; + } + function isCellWithinSelectionBounds({ + idx, + rowIdx + }) { + return rowIdx >= minRowIdx && rowIdx <= maxRowIdx && isColIdxWithinSelectionBounds(idx); + } + function isCellWithinViewportBounds({ + idx, + rowIdx + }) { + return isRowIdxWithinViewportBounds(rowIdx) && isColIdxWithinSelectionBounds(idx); + } + function isCellEditable(position) { + return isCellWithinViewportBounds(position) && isSelectedCellEditable({ + columns, + rows, + selectedPosition: position, + isGroupRow + }); + } + function selectCell(position, enableEditor) { + if (!isCellWithinSelectionBounds(position)) return; + commitEditorChanges(); + if (enableEditor && isCellEditable(position)) { + const row = rows[position.rowIdx]; + setSelectedPosition({ + ...position, + mode: 'EDIT', + row, + originalRow: row + }); + onSelectedCellChange?.(position); + } else if (isSamePosition(selectedPosition, position)) { + scrollIntoView(gridRef.current?.querySelector('[tabindex="0"]')); + } else { + setSelectedPosition({ + ...position, + mode: 'SELECT' + }); + onSelectedCellChange?.(position); + } + } + function scrollToColumn(idx) { + const { + current + } = gridRef; + if (!current) return; + if (idx > lastFrozenColumnIndex) { + const { + rowIdx + } = selectedPosition; + if (!isCellWithinSelectionBounds({ + rowIdx, + idx + })) return; + const { + clientWidth + } = current; + const column = columns[idx]; + const { + left, + width + } = columnMetrics.get(column); + let right = left + width; + const colSpan = getSelectedCellColSpan({ + rows, + topSummaryRows, + bottomSummaryRows, + rowIdx, + lastFrozenColumnIndex, + column, + isGroupRow + }); + if (colSpan !== undefined) { + const { + left, + width + } = columnMetrics.get(columns[column.idx + colSpan - 1]); + right = left + width; + } + const isCellAtLeftBoundary = left < scrollLeft + totalFrozenColumnWidth; + const isCellAtRightBoundary = right > clientWidth + scrollLeft; + const sign = isRtl ? -1 : 1; + if (isCellAtLeftBoundary) { + current.scrollLeft = (left - totalFrozenColumnWidth) * sign; + } else if (isCellAtRightBoundary) { + current.scrollLeft = (right - clientWidth) * sign; + } + } + } + function getNextPosition(key, ctrlKey, shiftKey) { + const { + idx, + rowIdx + } = selectedPosition; + const row = rows[rowIdx]; + const isRowSelected = selectedCellIsWithinSelectionBounds && idx === -1; + + if (key === leftKey && isRowSelected && isGroupRow(row) && !row.isExpanded && row.level !== 0) { + let parentRowIdx = -1; + for (let i = selectedPosition.rowIdx - 1; i >= 0; i--) { + const parentRow = rows[i]; + if (isGroupRow(parentRow) && parentRow.id === row.parentId) { + parentRowIdx = i; + break; + } + } + if (parentRowIdx !== -1) { + return { + idx, + rowIdx: parentRowIdx + }; + } + } + switch (key) { + case 'ArrowUp': + return { + idx, + rowIdx: rowIdx - 1 + }; + case 'ArrowDown': + return { + idx, + rowIdx: rowIdx + 1 + }; + case leftKey: + return { + idx: idx - 1, + rowIdx + }; + case rightKey: + return { + idx: idx + 1, + rowIdx + }; + case 'Tab': + return { + idx: idx + (shiftKey ? -1 : 1), + rowIdx + }; + case 'Home': + if (isRowSelected) return { + idx, + rowIdx: 0 + }; + return { + idx: 0, + rowIdx: ctrlKey ? minRowIdx : rowIdx + }; + case 'End': + if (isRowSelected) return { + idx, + rowIdx: rows.length - 1 + }; + return { + idx: maxColIdx, + rowIdx: ctrlKey ? maxRowIdx : rowIdx + }; + case 'PageUp': + { + if (selectedPosition.rowIdx === minRowIdx) return selectedPosition; + const nextRowY = getRowTop(rowIdx) + getRowHeight(rowIdx) - clientHeight; + return { + idx, + rowIdx: nextRowY > 0 ? findRowIdx(nextRowY) : 0 + }; + } + case 'PageDown': + { + if (selectedPosition.rowIdx >= rows.length) return selectedPosition; + const nextRowY = getRowTop(rowIdx) + clientHeight; + return { + idx, + rowIdx: nextRowY < totalRowHeight ? findRowIdx(nextRowY) : rows.length - 1 + }; + } + default: + return selectedPosition; + } + } + function navigate(event) { + const { + key, + shiftKey + } = event; + let mode = cellNavigationMode; + if (key === 'Tab') { + if (canExitGrid({ + shiftKey, + cellNavigationMode, + maxColIdx, + minRowIdx, + maxRowIdx, + selectedPosition + })) { + commitEditorChanges(); + return; + } + mode = cellNavigationMode === 'NONE' ? 'CHANGE_ROW' : cellNavigationMode; + } + + event.preventDefault(); + const ctrlKey = isCtrlKeyHeldDown(event); + const nextPosition = getNextPosition(key, ctrlKey, shiftKey); + if (isSamePosition(selectedPosition, nextPosition)) return; + const nextSelectedCellPosition = getNextSelectedCellPosition({ + columns, + colSpanColumns, + rows, + topSummaryRows, + bottomSummaryRows, + minRowIdx, + maxRowIdx, + lastFrozenColumnIndex, + cellNavigationMode: mode, + currentPosition: selectedPosition, + nextPosition, + isCellWithinBounds: isCellWithinSelectionBounds, + isGroupRow + }); + selectCell(nextSelectedCellPosition); + } + function getDraggedOverCellIdx(currentRowIdx) { + if (draggedOverRowIdx === undefined) return; + const { + rowIdx + } = selectedPosition; + const isDraggedOver = rowIdx < draggedOverRowIdx ? rowIdx < currentRowIdx && currentRowIdx <= draggedOverRowIdx : rowIdx > currentRowIdx && currentRowIdx >= draggedOverRowIdx; + return isDraggedOver ? selectedPosition.idx : undefined; + } + function getLayoutCssVars() { + if (flexWidthViewportColumns.length === 0) return layoutCssVars; + const newTemplateColumns = [...templateColumns]; + for (const column of flexWidthViewportColumns) { + newTemplateColumns[column.idx] = column.width; + } + return { + ...layoutCssVars, + gridTemplateColumns: newTemplateColumns.join(' ') + }; + } + function getDragHandle(rowIdx) { + if (selectedPosition.rowIdx !== rowIdx || selectedPosition.mode === 'EDIT' || hasGroups || + onFill == null) { + return; + } + return /*#__PURE__*/jsxRuntime.jsx(DragHandle, { + rows: rawRows, + columns: columns, + selectedPosition: selectedPosition, + isCellEditable: isCellEditable, + latestDraggedOverRowIdx: latestDraggedOverRowIdx, + onRowsChange: onRowsChange, + onFill: onFill, + setDragging: setDragging, + setDraggedOverRowIdx: setDraggedOverRowIdx + }); + } + function getCellEditor(rowIdx) { + if (selectedPosition.rowIdx !== rowIdx || selectedPosition.mode === 'SELECT') return; + const { + idx, + row + } = selectedPosition; + const column = columns[idx]; + const colSpan = getColSpan(column, lastFrozenColumnIndex, { + type: 'ROW', + row + }); + const closeEditor = () => { + setSelectedPosition(({ + idx, + rowIdx + }) => ({ + idx, + rowIdx, + mode: 'SELECT' + })); + }; + const onRowChange = (row, commitChanges) => { + if (commitChanges) { + updateRow(column, selectedPosition.rowIdx, row); + closeEditor(); + } else { + setSelectedPosition(position => ({ + ...position, + row + })); + } + }; + if (!isGroupRow(rows[selectedPosition.rowIdx]) && shouldCloseEditor?.(column, selectedPosition.originalRow, rows[selectedPosition.rowIdx])) { + closeEditor(); + } + return /*#__PURE__*/jsxRuntime.jsx(EditCell, { + column: column, + colSpan: colSpan, + row: row, + onRowChange: onRowChange, + closeEditor: closeEditor + }, column.key); + } + function getRowViewportColumns(rowIdx) { + const selectedColumn = columns[selectedPosition.idx]; + if ( + selectedColumn !== undefined && selectedPosition.rowIdx === rowIdx && !viewportColumns.includes(selectedColumn)) { + return selectedPosition.idx > colOverscanEndIdx ? [...viewportColumns, selectedColumn] : [...viewportColumns.slice(0, lastFrozenColumnIndex + 1), selectedColumn, ...viewportColumns.slice(lastFrozenColumnIndex + 1)]; + } + return viewportColumns; + } + function getViewportRows() { + const rowElements = []; + let startRowIndex = 0; + const { + idx: selectedIdx, + rowIdx: selectedRowIdx + } = selectedPosition; + const startRowIdx = selectedCellIsWithinViewportBounds && selectedRowIdx < rowOverscanStartIdx ? rowOverscanStartIdx - 1 : rowOverscanStartIdx; + const endRowIdx = selectedCellIsWithinViewportBounds && selectedRowIdx > rowOverscanEndIdx ? rowOverscanEndIdx + 1 : rowOverscanEndIdx; + for (let viewportRowIdx = startRowIdx; viewportRowIdx <= endRowIdx; viewportRowIdx++) { + const isRowOutsideViewport = viewportRowIdx === rowOverscanStartIdx - 1 || viewportRowIdx === rowOverscanEndIdx + 1; + const rowIdx = isRowOutsideViewport ? selectedRowIdx : viewportRowIdx; + let rowColumns = viewportColumns; + const selectedColumn = columns[selectedIdx]; + if (selectedColumn !== undefined) { + if (isRowOutsideViewport) { + rowColumns = [selectedColumn]; + } else { + rowColumns = getRowViewportColumns(rowIdx); + } + } + const row = rows[rowIdx]; + const gridRowStart = headerRowsCount + topSummaryRowsCount + rowIdx + 1; + if (isGroupRow(row)) { + ({ + startRowIndex + } = row); + const isGroupRowSelected = isSelectable && row.childRows.every(cr => selectedRows.has(rowKeyGetter(cr))); + rowElements.push( /*#__PURE__*/jsxRuntime.jsx(GroupRowRenderer, { + "aria-level": row.level + 1, + "aria-setsize": row.setSize, + "aria-posinset": row.posInSet + 1, + "aria-rowindex": headerRowsCount + topSummaryRowsCount + startRowIndex + 1, + "aria-selected": isSelectable ? isGroupRowSelected : undefined, + id: row.id, + groupKey: row.groupKey, + viewportColumns: rowColumns, + childRows: row.childRows, + rowIdx: rowIdx, + row: row, + gridRowStart: gridRowStart, + height: getRowHeight(rowIdx), + level: row.level, + isExpanded: row.isExpanded, + selectedCellIdx: selectedRowIdx === rowIdx ? selectedIdx : undefined, + isRowSelected: isGroupRowSelected, + selectGroup: selectGroupLatest, + toggleGroup: toggleGroupLatest + }, row.id)); + continue; + } + startRowIndex++; + let key; + let isRowSelected = false; + if (typeof rowKeyGetter === 'function') { + key = rowKeyGetter(row); + isRowSelected = selectedRows?.has(key) ?? false; + } else { + key = hasGroups ? startRowIndex : rowIdx; + } + rowElements.push(rowRenderer(key, { + 'aria-rowindex': headerRowsCount + topSummaryRowsCount + (hasGroups ? startRowIndex : rowIdx) + 1, + 'aria-selected': isSelectable ? isRowSelected : undefined, + rowIdx, + row, + viewportColumns: rowColumns, + isRowSelected, + onRowClick: onRowClickLatest, + onRowDoubleClick: onRowDoubleClickLatest, + rowClass, + gridRowStart, + height: getRowHeight(rowIdx), + copiedCellIdx: copiedCell !== null && copiedCell.row === row ? columns.findIndex(c => c.key === copiedCell.columnKey) : undefined, + selectedCellIdx: selectedRowIdx === rowIdx ? selectedIdx : undefined, + draggedOverCellIdx: getDraggedOverCellIdx(rowIdx), + setDraggedOverRowIdx: isDragging ? setDraggedOverRowIdx : undefined, + lastFrozenColumnIndex, + onRowChange: handleFormatterRowChangeLatest, + selectCell: selectViewportCellLatest, + selectedCellDragHandle: getDragHandle(rowIdx), + selectedCellEditor: getCellEditor(rowIdx) + })); + } + return rowElements; + } + + if (selectedPosition.idx > maxColIdx || selectedPosition.rowIdx > maxRowIdx) { + setSelectedPosition(initialPosition); + setDraggedOverRowIdx(undefined); + } + let templateRows = `${headerRowHeight}px`; + if (topSummaryRowsCount > 0) { + templateRows += ` repeat(${topSummaryRowsCount}, ${summaryRowHeight}px)`; + } + if (rows.length > 0) { + templateRows += gridTemplateRows; + } + if (bottomSummaryRowsCount > 0) { + templateRows += ` repeat(${bottomSummaryRowsCount}, ${summaryRowHeight}px)`; + } + const isGroupRowFocused = selectedPosition.idx === -1 && selectedPosition.rowIdx !== -2; + return /*#__PURE__*/jsxRuntime.jsxs("div", { + role: hasGroups ? 'treegrid' : 'grid', + "aria-label": ariaLabel, + "aria-labelledby": ariaLabelledBy, + "aria-describedby": ariaDescribedBy, + "aria-multiselectable": isSelectable ? true : undefined, + "aria-colcount": columns.length, + "aria-rowcount": headerRowsCount + rowsCount + summaryRowsCount, + className: clsx(rootClassname, className, isDragging && viewportDraggingClassname), + style: { + ...style, + scrollPaddingInlineStart: selectedPosition.idx > lastFrozenColumnIndex ? `${totalFrozenColumnWidth}px` : undefined, + scrollPaddingBlock: selectedPosition.rowIdx >= 0 && selectedPosition.rowIdx < rows.length ? `${headerRowHeight + topSummaryRowsCount * summaryRowHeight}px ${bottomSummaryRowsCount * summaryRowHeight}px` : undefined, + gridTemplateRows: templateRows, + '--rdg-header-row-height': `${headerRowHeight}px`, + '--rdg-summary-row-height': `${summaryRowHeight}px`, + '--rdg-sign': isRtl ? -1 : 1, + ...getLayoutCssVars() + }, + dir: direction, + ref: gridRef, + onScroll: handleScroll, + onKeyDown: handleKeyDown, + "data-testid": testId, + children: [hasGroups && /*#__PURE__*/jsxRuntime.jsx("div", { + ref: rowRef, + tabIndex: isGroupRowFocused ? 0 : -1, + className: clsx(focusSinkClassname, isGroupRowFocused && [rowSelected, lastFrozenColumnIndex !== -1 && rowSelectedWithFrozenCell]), + style: { + gridRowStart: selectedPosition.rowIdx + 2 + }, + onKeyDown: handleKeyDown + }), /*#__PURE__*/jsxRuntime.jsxs(DataGridDefaultComponentsProvider, { + value: defaultGridComponents, + children: [/*#__PURE__*/jsxRuntime.jsx(HeaderRow$1, { + columns: getRowViewportColumns(-1), + onColumnResize: handleColumnResizeLatest, + allRowsSelected: allRowsSelected, + onAllRowsSelectionChange: selectAllRowsLatest, + sortColumns: sortColumns, + onSortColumnsChange: onSortColumnsChangeLatest, + lastFrozenColumnIndex: lastFrozenColumnIndex, + selectedCellIdx: selectedPosition.rowIdx === minRowIdx ? selectedPosition.idx : undefined, + selectCell: selectHeaderCellLatest, + shouldFocusGrid: !selectedCellIsWithinSelectionBounds, + direction: direction + }), rows.length === 0 && noRowsFallback ? noRowsFallback : /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, { + children: [topSummaryRows?.map((row, rowIdx) => { + const gridRowStart = headerRowsCount + rowIdx + 1; + const summaryRowIdx = rowIdx + minRowIdx + 1; + const isSummaryRowSelected = selectedPosition.rowIdx === summaryRowIdx; + const top = headerRowHeight + summaryRowHeight * rowIdx; + return /*#__PURE__*/jsxRuntime.jsx(SummaryRow$1, { + "aria-rowindex": gridRowStart, + rowIdx: rowIdx, + gridRowStart: gridRowStart, + row: row, + top: top, + bottom: undefined, + lastTopRowIdx: topSummaryRowsCount - 1, + viewportColumns: getRowViewportColumns(summaryRowIdx), + lastFrozenColumnIndex: lastFrozenColumnIndex, + selectedCellIdx: isSummaryRowSelected ? selectedPosition.idx : undefined, + selectCell: selectTopSummaryCellLatest + }, rowIdx); + }), /*#__PURE__*/jsxRuntime.jsx(RowSelectionChangeProvider, { + value: selectRowLatest, + children: getViewportRows() + }), bottomSummaryRows?.map((row, rowIdx) => { + const gridRowStart = headerRowsCount + topSummaryRowsCount + rows.length + rowIdx + 1; + const summaryRowIdx = rows.length + rowIdx; + const isSummaryRowSelected = selectedPosition.rowIdx === summaryRowIdx; + const top = clientHeight > totalRowHeight ? gridHeight - summaryRowHeight * (bottomSummaryRows.length - rowIdx) : undefined; + const bottom = top === undefined ? summaryRowHeight * (bottomSummaryRows.length - 1 - rowIdx) : undefined; + return /*#__PURE__*/jsxRuntime.jsx(SummaryRow$1, { + "aria-rowindex": headerRowsCount + topSummaryRowsCount + rowsCount + rowIdx + 1, + rowIdx: rowIdx, + gridRowStart: gridRowStart, + row: row, + top: top, + bottom: bottom, + lastTopRowIdx: undefined, + viewportColumns: getRowViewportColumns(summaryRowIdx), + lastFrozenColumnIndex: lastFrozenColumnIndex, + selectedCellIdx: isSummaryRowSelected ? selectedPosition.idx : undefined, + selectCell: selectBottomSummaryCellLatest + }, rowIdx); + })] + }), renderMeasuringCells(viewportColumns)] + })] + }); +} +function isSamePosition(p1, p2) { + return p1.idx === p2.idx && p1.rowIdx === p2.rowIdx; +} +const DataGrid$1 = /*#__PURE__*/react.forwardRef(DataGrid); + +const textEditorInternalClassname = "t7vyx3i7-0-0-beta-19"; +const textEditorClassname = `rdg-text-editor ${textEditorInternalClassname}`; +function autoFocusAndSelect(input) { + input?.focus(); + input?.select(); +} +function textEditor({ + row, + column, + onRowChange, + onClose +}) { + return /*#__PURE__*/jsxRuntime.jsx("input", { + className: textEditorClassname, + ref: autoFocusAndSelect, + value: row[column.key], + onChange: event => onRowChange({ + ...row, + [column.key]: event.target.value + }), + onBlur: () => onClose(true) + }); +} + +exports.DataGridDefaultComponentsProvider = DataGridDefaultComponentsProvider; +exports.Row = RowComponent$1; +exports.SELECT_COLUMN_KEY = SELECT_COLUMN_KEY; +exports.SelectCellFormatter = SelectCellFormatter; +exports.SelectColumn = SelectColumn; +exports.ToggleGroup = ToggleGroup; +exports.checkboxFormatter = checkboxFormatter; +exports.default = DataGrid$1; +exports.headerRenderer = headerRenderer; +exports.sortIcon = sortIcon; +exports.sortPriority = sortPriority; +exports.textEditor = textEditor; +exports.toggleGroupFormatter = toggleGroupFormatter; +exports.useFocusRef = useFocusRef; +exports.useRowSelection = useRowSelection; +exports.valueFormatter = valueFormatter; +//# sourceMappingURL=bundle.cjs.map diff --git a/lib/bundle.cjs.map b/lib/bundle.cjs.map new file mode 100644 index 0000000000..e692c1cf9c --- /dev/null +++ b/lib/bundle.cjs.map @@ -0,0 +1 @@ +{"version":3,"file":"bundle.cjs","sources":["../src/style/cell.ts","../src/style/core.ts","../src/style/row.ts","../src/formatters/checkboxFormatter.tsx","../src/hooks/useLayoutEffect.ts","../src/hooks/useFocusRef.ts","../src/DataGridDefaultComponentsProvider.ts","../src/formatters/SelectCellFormatter.tsx","../src/formatters/valueFormatter.tsx","../src/formatters/toggleGroupFormatter.tsx","../src/hooks/useRowSelection.ts","../src/Columns.tsx","../src/utils/colSpanUtils.ts","../src/utils/domUtils.ts","../src/utils/keyboardUtils.ts","../src/utils/renderMeasuringCells.tsx","../src/utils/selectedCellUtils.ts","../src/utils/styleUtils.ts","../src/utils/index.ts","../src/hooks/useCalculatedColumns.ts","../src/hooks/useGridDimensions.ts","../src/hooks/useLatestFunc.ts","../src/hooks/useRovingCellRef.ts","../src/hooks/useViewportColumns.ts","../src/hooks/useViewportRows.ts","../src/headerRenderer.tsx","../src/HeaderCell.tsx","../src/HeaderRow.tsx","../src/Cell.tsx","../src/Row.tsx","../src/GroupCell.tsx","../src/GroupRow.tsx","../src/SummaryCell.tsx","../src/SummaryRow.tsx","../src/EditCell.tsx","../src/DragHandle.tsx","../src/sortStatus.tsx","../src/DataGrid.tsx","../src/editors/textEditor.tsx"],"sourcesContent":["import { css } from '@linaria/core';\n\nexport const cell = css`\n @layer rdg.Cell {\n /* max-content does not work with size containment\n * dynamically switching between different containment styles incurs a heavy relayout penalty\n * Chromium bug: at odd zoom levels or subpixel positioning, layout/paint containment can make cell borders disappear\n * https://bugs.chromium.org/p/chromium/issues/detail?id=1326946\n */\n contain: style;\n position: relative; /* needed for absolute positioning to work */\n padding-block: 0;\n padding-inline: 8px;\n border-inline-end: 1px solid var(--rdg-border-color);\n border-block-end: 1px solid var(--rdg-border-color);\n grid-row-start: var(--rdg-grid-row-start);\n background-color: inherit;\n\n white-space: nowrap;\n overflow: hidden;\n overflow: clip;\n text-overflow: ellipsis;\n outline: none;\n\n &[aria-selected='true'] {\n outline: 2px solid var(--rdg-selection-color);\n outline-offset: -2px;\n }\n }\n`;\n\nexport const cellClassname = `rdg-cell ${cell}`;\n\nexport const cellFrozen = css`\n @layer rdg.Cell {\n position: sticky;\n /* Should have a higher value than 0 to show up above unfrozen cells */\n z-index: 1;\n }\n`;\n\nexport const cellFrozenClassname = `rdg-cell-frozen ${cellFrozen}`;\n\nexport const cellFrozenLast = css`\n @layer rdg.Cell {\n box-shadow: calc(2px * var(--rdg-sign)) 0 5px -2px rgba(136, 136, 136, 0.3);\n }\n`;\n\nexport const cellFrozenLastClassname = `rdg-cell-frozen-last ${cellFrozenLast}`;\n","import { css } from '@linaria/core';\nimport { row } from './row';\n\nconst lightTheme = `\n --rdg-color: #000;\n --rdg-border-color: #ddd;\n --rdg-summary-border-color: #aaa;\n --rdg-background-color: hsl(0deg 0% 100%);\n --rdg-header-background-color: hsl(0deg 0% 97.5%);\n --rdg-row-hover-background-color: hsl(0deg 0% 96%);\n --rdg-row-selected-background-color: hsl(207deg 76% 92%);\n --rdg-row-selected-hover-background-color: hsl(207deg 76% 88%);\n\n --rdg-checkbox-color: hsl(207deg 100% 29%);\n --rdg-checkbox-focus-color: hsl(207deg 100% 69%);\n --rdg-checkbox-disabled-border-color: #ccc;\n --rdg-checkbox-disabled-background-color: #ddd;\n`;\n\nconst darkTheme = `\n --rdg-color: #ddd;\n --rdg-border-color: #444;\n --rdg-summary-border-color: #555;\n --rdg-background-color: hsl(0deg 0% 13%);\n --rdg-header-background-color: hsl(0deg 0% 10.5%);\n --rdg-row-hover-background-color: hsl(0deg 0% 9%);\n --rdg-row-selected-background-color: hsl(207deg 76% 42%);\n --rdg-row-selected-hover-background-color: hsl(207deg 76% 38%);\n\n --rdg-checkbox-color: hsl(207deg 100% 79%);\n --rdg-checkbox-focus-color: hsl(207deg 100% 89%);\n --rdg-checkbox-disabled-border-color: #000;\n --rdg-checkbox-disabled-background-color: #333;\n`;\n\nconst root = css`\n @layer rdg {\n @layer Defaults,\n FocusSink,\n CheckboxInput,\n CheckboxIcon,\n CheckboxLabel,\n Cell,\n HeaderCell,\n SummaryCell,\n EditCell,\n Row,\n HeaderRow,\n SummaryRow,\n GroupedRow,\n Root;\n\n @layer Defaults {\n *,\n *::before,\n *::after {\n box-sizing: inherit;\n }\n }\n\n @layer Root {\n ${lightTheme}\n --rdg-selection-color: #66afe9;\n --rdg-font-size: 14px;\n\n display: grid;\n\n color-scheme: var(--rdg-color-scheme, light dark);\n\n /* https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context */\n /* We set a stacking context so internal elements don't render on top of external elements. */\n contain: strict;\n content-visibility: auto;\n block-size: 350px;\n border: 1px solid var(--rdg-border-color);\n box-sizing: border-box;\n overflow: auto;\n background-color: var(--rdg-background-color);\n color: var(--rdg-color);\n font-size: var(--rdg-font-size);\n\n /* needed on Firefox */\n &::before {\n content: '';\n grid-column: 1/-1;\n grid-row: 1/-1;\n }\n\n &.rdg-dark {\n --rdg-color-scheme: dark;\n ${darkTheme}\n }\n\n &.rdg-light {\n --rdg-color-scheme: light;\n }\n\n @media (prefers-color-scheme: dark) {\n &:not(.rdg-light) {\n ${darkTheme}\n }\n }\n }\n }\n`;\n\nexport const rootClassname = `rdg ${root}`;\n\nconst viewportDragging = css`\n @layer rdg.Root {\n user-select: none;\n\n & .${row} {\n cursor: move;\n }\n }\n`;\n\nexport const viewportDraggingClassname = `rdg-viewport-dragging ${viewportDragging}`;\n\nexport const focusSinkClassname = css`\n @layer rdg.FocusSink {\n grid-column: 1/-1;\n pointer-events: none;\n /* Should have a higher value than 2 to show up above header row */\n z-index: 3;\n }\n`;\n","import { css } from '@linaria/core';\n\nexport const row = css`\n @layer rdg.Row {\n display: contents;\n line-height: var(--rdg-row-height);\n background-color: var(--rdg-background-color);\n\n &:hover {\n background-color: var(--rdg-row-hover-background-color);\n }\n\n &[aria-selected='true'] {\n background-color: var(--rdg-row-selected-background-color);\n\n &:hover {\n background-color: var(--rdg-row-selected-hover-background-color);\n }\n }\n }\n`;\n\nexport const rowClassname = `rdg-row ${row}`;\n\nexport const rowSelected = css`\n @layer rdg.FocusSink {\n outline: 2px solid var(--rdg-selection-color);\n outline-offset: -2px;\n }\n`;\n\nexport const rowSelectedClassname = `rdg-row-selected`;\n\nexport const rowSelectedWithFrozenCell = css`\n @layer rdg.FocusSink {\n &::before {\n content: '';\n display: inline-block;\n height: 100%;\n position: sticky;\n inset-inline-start: 0;\n border-inline-start: 2px solid var(--rdg-selection-color);\n }\n }\n`;\n","import clsx from 'clsx';\nimport { css } from '@linaria/core';\n\nimport type { CheckboxFormatterProps } from '../types';\n\nconst checkboxLabel = css`\n @layer rdg.CheckboxLabel {\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n inset: 0;\n margin-inline-end: 1px; /* align checkbox in row group cell */\n }\n`;\n\nconst checkboxLabelClassname = `rdg-checkbox-label ${checkboxLabel}`;\n\nconst checkboxInput = css`\n @layer rdg.CheckboxInput {\n all: unset;\n }\n`;\n\nconst checkboxInputClassname = `rdg-checkbox-input ${checkboxInput}`;\n\nconst checkbox = css`\n @layer rdg.CheckboxIcon {\n content: '';\n inline-size: 20px;\n block-size: 20px;\n border: 2px solid var(--rdg-border-color);\n background-color: var(--rdg-background-color);\n\n .${checkboxInput}:checked + & {\n background-color: var(--rdg-checkbox-color);\n outline: 4px solid var(--rdg-background-color);\n outline-offset: -6px;\n }\n\n .${checkboxInput}:focus + & {\n border-color: var(--rdg-checkbox-focus-color);\n }\n }\n`;\n\nconst checkboxClassname = `rdg-checkbox ${checkbox}`;\n\nconst checkboxLabelDisabled = css`\n @layer rdg.CheckboxLabel {\n cursor: default;\n\n .${checkbox} {\n border-color: var(--rdg-checkbox-disabled-border-color);\n background-color: var(--rdg-checkbox-disabled-background-color);\n }\n }\n`;\n\nconst checkboxLabelDisabledClassname = `rdg-checkbox-label-disabled ${checkboxLabelDisabled}`;\n\nexport function checkboxFormatter(\n { onChange, ...props }: CheckboxFormatterProps,\n ref: React.RefObject\n) {\n function handleChange(e: React.ChangeEvent) {\n onChange(e.target.checked, (e.nativeEvent as MouseEvent).shiftKey);\n }\n\n return (\n \n \n
\n \n );\n}\n","// eslint-disable-next-line @typescript-eslint/no-restricted-imports\nimport { useEffect, useLayoutEffect as useOriginalLayoutEffect } from 'react';\n\n// Silence silly warning\n// https://reactjs.org/link/uselayouteffect-ssr\nexport const useLayoutEffect = typeof window === 'undefined' ? useEffect : useOriginalLayoutEffect;\n","import { useRef } from 'react';\nimport { useLayoutEffect } from './useLayoutEffect';\n\nexport function useFocusRef(isSelected: boolean) {\n const ref = useRef(null);\n\n useLayoutEffect(() => {\n if (!isSelected) return;\n ref.current?.focus({ preventScroll: true });\n }, [isSelected]);\n\n return {\n ref,\n tabIndex: isSelected ? 0 : -1\n };\n}\n","import { createContext, useContext } from 'react';\n\nimport type { Renderers, Maybe } from './types';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst DataGridDefaultComponentsContext = createContext>>(undefined);\n\nexport const DataGridDefaultComponentsProvider = DataGridDefaultComponentsContext.Provider;\n\nexport function useDefaultComponents(): Maybe> {\n return useContext(DataGridDefaultComponentsContext);\n}\n","import { useFocusRef } from '../hooks/useFocusRef';\nimport { useDefaultComponents } from '../DataGridDefaultComponentsProvider';\nimport type { CheckboxFormatterProps } from '../types';\n\ntype SharedInputProps = Pick;\n\ninterface SelectCellFormatterProps extends SharedInputProps {\n isCellSelected: boolean;\n value: boolean;\n onChange: (value: boolean, isShiftClick: boolean) => void;\n}\n\nexport function SelectCellFormatter({\n value,\n isCellSelected,\n disabled,\n onChange,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy\n}: SelectCellFormatterProps) {\n const { ref, tabIndex } = useFocusRef(isCellSelected);\n const checkboxFormatter = useDefaultComponents()!.checkboxFormatter!;\n\n return (\n <>\n {checkboxFormatter(\n {\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n tabIndex,\n disabled,\n checked: value,\n onChange\n },\n ref\n )}\n \n );\n}\n","import type { FormatterProps } from '../types';\n\nexport function valueFormatter(props: FormatterProps) {\n try {\n return <>{props.row[props.column.key as keyof R]};\n } catch {\n return null;\n }\n}\n","import { css } from '@linaria/core';\nimport type { GroupFormatterProps } from '../types';\nimport { useFocusRef } from '../hooks/useFocusRef';\n\nconst groupCellContent = css`\n @layer rdg.GroupCellContent {\n outline: none;\n }\n`;\n\nconst groupCellContentClassname = `rdg-group-cell-content ${groupCellContent}`;\n\nconst caret = css`\n @layer rdg.GroupCellCaret {\n margin-inline-start: 4px;\n stroke: currentColor;\n stroke-width: 1.5px;\n fill: transparent;\n vertical-align: middle;\n\n > path {\n transition: d 0.1s;\n }\n }\n`;\n\nconst caretClassname = `rdg-caret ${caret}`;\n\nexport function toggleGroupFormatter(props: GroupFormatterProps) {\n return ;\n}\n\nexport function ToggleGroup({\n groupKey,\n isExpanded,\n isCellSelected,\n toggleGroup\n}: GroupFormatterProps) {\n const { ref, tabIndex } = useFocusRef(isCellSelected);\n\n function handleKeyDown({ key }: React.KeyboardEvent) {\n if (key === 'Enter') {\n toggleGroup();\n }\n }\n\n const d = isExpanded ? 'M1 1 L 7 7 L 13 1' : 'M1 7 L 7 1 L 13 7';\n\n return (\n \n {groupKey as string}\n \n \n \n \n );\n}\n","import { createContext, useContext } from 'react';\nimport type { SelectRowEvent } from '../types';\n\nconst RowSelectionContext = createContext(undefined);\n\nexport const RowSelectionProvider = RowSelectionContext.Provider;\n\nconst RowSelectionChangeContext = createContext<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ((selectRowEvent: SelectRowEvent) => void) | undefined\n>(undefined);\n\nexport const RowSelectionChangeProvider = RowSelectionChangeContext.Provider;\n\nexport function useRowSelection(): [boolean, (selectRowEvent: SelectRowEvent) => void] {\n const rowSelectionContext = useContext(RowSelectionContext);\n const rowSelectionChangeContext = useContext(RowSelectionChangeContext);\n\n if (rowSelectionContext === undefined || rowSelectionChangeContext === undefined) {\n throw new Error('useRowSelection must be used within DataGrid cells');\n }\n\n return [rowSelectionContext, rowSelectionChangeContext];\n}\n","import { SelectCellFormatter } from './formatters';\nimport { useRowSelection } from './hooks/useRowSelection';\nimport type { Column, FormatterProps, GroupFormatterProps } from './types';\n\nexport const SELECT_COLUMN_KEY = 'select-row';\n\nfunction SelectFormatter(props: FormatterProps) {\n const [isRowSelected, onRowSelectionChange] = useRowSelection();\n\n return (\n {\n onRowSelectionChange({ row: props.row, checked, isShiftClick });\n }}\n />\n );\n}\n\nfunction SelectGroupFormatter(props: GroupFormatterProps) {\n const [isRowSelected, onRowSelectionChange] = useRowSelection();\n\n return (\n {\n onRowSelectionChange({ row: props.row, checked, isShiftClick: false });\n }}\n />\n );\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const SelectColumn: Column = {\n key: SELECT_COLUMN_KEY,\n name: '',\n width: 35,\n minWidth: 35,\n maxWidth: 35,\n resizable: false,\n sortable: false,\n frozen: true,\n headerRenderer(props) {\n return (\n \n );\n },\n formatter(props) {\n return ;\n },\n groupFormatter(props) {\n return ;\n }\n};\n","import type { CalculatedColumn, ColSpanArgs } from '../types';\n\nexport function getColSpan(\n column: CalculatedColumn,\n lastFrozenColumnIndex: number,\n args: ColSpanArgs\n): number | undefined {\n const colSpan = typeof column.colSpan === 'function' ? column.colSpan(args) : 1;\n if (\n Number.isInteger(colSpan) &&\n colSpan! > 1 &&\n // ignore colSpan if it spans over both frozen and regular columns\n (!column.frozen || column.idx + colSpan! - 1 <= lastFrozenColumnIndex)\n ) {\n return colSpan!;\n }\n return undefined;\n}\n","import type { Maybe } from '../types';\n\nexport function stopPropagation(event: React.SyntheticEvent) {\n event.stopPropagation();\n}\n\nexport function scrollIntoView(element: Maybe) {\n element?.scrollIntoView({ inline: 'nearest', block: 'nearest' });\n}\n","// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values\nconst nonInputKeys = new Set([\n // Special keys\n 'Unidentified',\n // Modifier keys\n 'Alt',\n 'AltGraph',\n 'CapsLock',\n 'Control',\n 'Fn',\n 'FnLock',\n 'Meta',\n 'NumLock',\n 'ScrollLock',\n 'Shift',\n // Whitespace keys\n 'Tab',\n // Navigation keys\n 'ArrowDown',\n 'ArrowLeft',\n 'ArrowRight',\n 'ArrowUp',\n 'End',\n 'Home',\n 'PageDown',\n 'PageUp',\n // Editing\n 'Insert',\n // UI keys\n 'ContextMenu',\n 'Escape',\n 'Pause',\n 'Play',\n // Device keys\n 'PrintScreen',\n // Function keys\n 'F1',\n // 'F2', /!\\ specifically allowed, do not edit\n 'F3',\n 'F4',\n 'F5',\n 'F6',\n 'F7',\n 'F8',\n 'F9',\n 'F10',\n 'F11',\n 'F12'\n]);\n\nexport function isCtrlKeyHeldDown(e: React.KeyboardEvent): boolean {\n return (e.ctrlKey || e.metaKey) && e.key !== 'Control';\n}\n\nexport function isDefaultCellInput(event: React.KeyboardEvent): boolean {\n return !nonInputKeys.has(event.key);\n}\n\n/**\n * By default, the following navigation keys are enabled while an editor is open, under specific conditions:\n * - Tab:\n * - The editor must be an , a