/* * Copyright 2016 Palantir Technologies, Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import classNames from "classnames"; import { Component } from "react"; import * as Classes from "../common/classes"; import type { RowIndices } from "../common/grid"; import type { ClientCoordinates } from "../interactions/dragTypes"; import type { IndexedResizeCallback } from "../interactions/resizable"; import { Orientation } from "../interactions/resizeHandle"; import { RegionCardinality, Regions } from "../regions"; import { Header, type HeaderProps } from "./header"; import { RowHeaderCell, type RowHeaderCellProps } from "./rowHeaderCell"; export type RowHeaderRenderer = (rowIndex: number) => React.ReactElement; export interface RowHeights { minRowHeight: number; maxRowHeight: number; defaultRowHeight: number; } export interface RowHeaderProps extends HeaderProps, RowHeights, RowIndices { /** * A callback invoked when user is done resizing the column */ onRowHeightChanged: IndexedResizeCallback; /** * Renders the cell for each row header */ rowHeaderCellRenderer?: RowHeaderRenderer; /** * Called on component mount. */ onMount?: (whichHeader: "column" | "row") => void; } export class RowHeader extends Component { public static defaultProps = { rowHeaderCellRenderer: renderDefaultRowHeader, }; public componentDidMount() { this.props.onMount?.("row"); } public render() { const { // from RowHeaderProps onRowHeightChanged, rowHeaderCellRenderer, // from RowHeights minRowHeight: minSize, maxRowHeight: maxSize, defaultRowHeight, // from RowIndices rowIndexStart: indexStart, rowIndexEnd: indexEnd, // from HeaderProps ...spreadableProps } = this.props; return (
); } private wrapCells = (cells: Array>) => { const { rowIndexStart, grid } = this.props; const tableHeight = grid.getRect().height; const scrollTopCorrection = this.props.grid.getCumulativeHeightBefore(rowIndexStart); const style: React.CSSProperties = { // reduce the height to clamp the sliding window as we approach the final headers; otherwise, // we'll have tons of useless whitespace at the end. height: tableHeight - scrollTopCorrection, // only header cells in view will render, but we need to reposition them to stay in view // as we scroll vertically. transform: `translateY(${scrollTopCorrection || 0}px)`, }; // add a wrapper set to the full-table height to ensure container styles stretch from the first // cell all the way to the last return (
{cells}
); }; private convertPointToRow = (clientXOrY: number, useMidpoint?: boolean) => { return this.props.locator?.convertPointToRow(clientXOrY, useMidpoint); }; private getCellExtremaClasses = (index: number, indexEnd: number) => { return this.props.grid.getExtremaClasses(index, 0, indexEnd, 1); }; private getRowHeight = (index: number) => { return this.props.grid.getRowRect(index).height; }; private getDragCoordinate = (clientCoords: ClientCoordinates) => { return clientCoords[1]; // y-coordinate }; private getMouseCoordinate = (event: MouseEvent) => { return event.clientY; }; private handleResizeEnd = (index: number, size: number) => { this.props.onResizeGuide(null); this.props.onRowHeightChanged(index, size); }; private handleSizeChanged = (index: number, size: number) => { const rect = this.props.grid.getRowRect(index); this.props.onResizeGuide([rect.top + size]); }; private isCellSelected = (index: number) => { return Regions.hasFullRow(this.props.selectedRegions!, index); }; private isGhostIndex = (index: number) => { return this.props.grid.isGhostIndex(index, -1); }; private renderGhostCell = (index: number, extremaClasses: string[]) => { const rect = this.props.grid.getGhostCellRect(index, 0); return ( ); }; private toRegion = (index1: number, index2?: number) => { // the `this` value is messed up for Regions.row, so we have to have a wrapper function here return Regions.row(index1, index2); }; } /** * A default implementation of `RowHeaderRenderer` that displays 1-indexed * numbers for each row. */ export function renderDefaultRowHeader(rowIndex: number) { return ; }