From 7f9fd89ea34ada050834238d78c9e73828b62af4 Mon Sep 17 00:00:00 2001 From: Aman Mahajan Date: Tue, 17 Dec 2024 16:50:27 -0600 Subject: [PATCH] Update docs (#3631) Add some documentation --- README.md | 325 +++++++++++++++++++++++++++++++++++++++++++++-- eslint.config.js | 19 +++ package.json | 1 + src/DataGrid.tsx | 2 +- src/index.ts | 7 +- src/types.ts | 16 ++- 6 files changed, 349 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 4a80556fa8..ef726156e7 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ - [Cell copy / pasting](https://adazzle.github.io/react-data-grid/#/AllFeatures) - [Cell value dragging / filling](https://adazzle.github.io/react-data-grid/#/AllFeatures) - [Customizable Renderers](https://adazzle.github.io/react-data-grid/#/CustomizableRenderers) -- Right-to-left (RTL) support. We recommend using Firefox as Chrome has a [bug](https://bugs.chromium.org/p/chromium/issues/detail?id=1140374) with frozen columns, and the [`:dir` pseudo class](https://developer.mozilla.org/en-US/docs/Web/CSS/:dir) is not supported +- Right-to-left (RTL) support. We recommend using Firefox as Chrome has a [bug](https://bugs.chromium.org/p/chromium/issues/detail?id=1140374) with frozen columns. ## Links @@ -87,7 +87,7 @@ function App() { #### `` -##### Props +##### DataGridProps ###### `columns: readonly Column[]` @@ -103,9 +103,11 @@ An array of rows, the rows data can be of any type. ###### `topSummaryRows?: Maybe` +An optional array of summary rows, usually used to display total values for example. `topSummaryRows` are pinned at the top of the rows view and the vertical scroll bar will not scroll these rows. + ###### `bottomSummaryRows?: Maybe` -An optional array of summary rows, usually used to display total values for example. +An optional array of summary rows, usually used to display total values for example. `bottomSummaryRows` are pinned at the bottom of the rows view and the vertical scroll bar will not scroll these rows. ###### `rowKeyGetter?: Maybe<(row: R) => K>` @@ -167,23 +169,116 @@ A number defining the height of summary rows. ###### `selectedRows?: Maybe>` +A set of selected row keys. `rowKeyGetter` is required for row selection to work. + ###### `isRowSelectionDisabled?: Maybe<(row: NoInfer) => boolean>` +A function used to disable row selection on certain rows. + ###### `onSelectedRowsChange?: Maybe<(selectedRows: Set) => void>` +A function called when row selection is changed. + +```tsx +import { useState } from 'react'; +import DataGrid, { SelectColumn } from 'react-data-grid'; + +const rows: readonly Rows[] = [...]; + +const columns: readonly Column[] = [ + SelectColumn, + // other columns +]; + +function MyGrid() { + const [selectedRows, setSelectedRows] = useState((): ReadonlySet => new Set()); + + return ( + + ); +} + +function rowKeyGetter(row: Row) { + return row.id; +} + +function isRowSelectionDisabled(row: Row) { + return !row.isActive; +} +``` + ###### `sortColumns?: Maybe` +An array of sorted columns. + ###### `onSortColumnsChange?: Maybe<(sortColumns: SortColumn[]) => void>` -###### `defaultColumnOptions?: Maybe>` +A function called when sorting is changed -###### `groupBy?: Maybe` +```tsx +import { useState } from 'react'; +import DataGrid, { SelectColumn } from 'react-data-grid'; -###### `rowGrouper?: Maybe<(rows: readonly R[], columnKey: string) => Record>` +const rows: readonly Rows[] = [...]; -###### `expandedGroupIds?: Maybe>` +const columns: readonly Column[] = [ + { + key: 'name', + name: 'Name', + sortable: true + }, + // other columns +]; -###### `onExpandedGroupIdsChange?: Maybe<(expandedGroupIds: Set) => void>` +function MyGrid() { + const [sortColumns, setSortColumns] = useState([]); + + return ( + + ); +} +``` + +Grid can be sorted on multiple columns using `ctrl (command) + click`. To disable multiple column sorting, change the `onSortColumnsChange` function to + +```tsx +onSortColumnsChange(sortColumns: SortColumn[]) { + setSortColumns(sortColumns.slice(-1)); +} +``` + +###### `defaultColumnOptions?: Maybe>` + +Column options that are applied to all the columns + +```tsx +function MyGrid() { + return ( + + ); +} +``` ###### `onFill?: Maybe<(event: FillEvent) => R>` @@ -193,12 +288,99 @@ A number defining the height of summary rows. ###### `onCellClick?: Maybe<(args: CellClickArgs, event: CellMouseEvent) => void>` +Triggered when a cell is clicked. The default behavior is to select the cell. Call `preventGridDefault` to prevent the default behavior + +```tsx +function onCellClick(args: CellClickArgs, event: CellMouseEvent) { + if (args.column.key === 'id') { + event.preventGridDefault(); + } +} + +; +``` + +This event can be used to open cell editor on single click + +```tsx +function onCellClick(args: CellClickArgs, event: CellMouseEvent) { + if (args.column.key === 'id') { + event.preventGridDefault(); + args.selectCell(true); + } +} +``` + +Arguments: + +`args: CellClickArgs` + +- `args.rowIdx`: `number` - row index of the currently selected cell +- `args.row`: `R` - row object of the currently selected cell +- `args.column`: `CalculatedColumn` - column object of the currently selected cell +- `args.selectCell`: `(enableEditor?: boolean) => void` - function to manually select the cell and optionally pass `true` to start editing + +`event` extends `React.MouseEvent` + +- `event.preventGridDefault:`: `() => void` +- `event.isGridDefaultPrevented`: `boolean` + ###### `onCellDoubleClick?: Maybe<(args: CellClickArgs, event: CellMouseEvent) => void>` +Triggered when a cell is double clicked. The default behavior is to open the editor if the cell is editable. Call `preventGridDefault` to prevent the default behavior + +```tsx +function onCellDoubleClick(args: CellClickArgs, event: CellMouseEvent) { + if (args.column.key === 'id') { + event.preventGridDefault(); + } +} + +; +``` + ###### `onCellContextMenu?: Maybe<(args: CellClickArgs, event: CellMouseEvent) => void>` +Triggered when a cell is right clicked. The default behavior is to select the cell. Call `preventGridDefault` to prevent the default behavior + +```tsx +function onCellContextMenu(args: CellClickArgs, event: CellMouseEvent) { + if (args.column.key === 'id') { + event.preventGridDefault(); + } +} + +; +``` + ###### `onCellKeyDown?: Maybe<(args: CellKeyDownArgs, event: CellKeyboardEvent) => void>` +A function called when keydown event is triggered on a cell. This event can be used to customize cell navigation and editing behavior. + +**Examples** + +- Prevent editing on `Enter` + +```tsx +function onCellKeyDown(args: CellKeyDownArgs, event: CellKeyboardEvent) { + if (args.mode === 'SELECT' && event.key === 'Enter') { + event.preventGridDefault(); + } +} +``` + +- Prevent navigation on `Tab` + +```tsx +function onCellKeyDown(args: CellKeyDownArgs, event: CellKeyboardEvent) { + if (args.mode === 'SELECT' && event.key === 'Tab') { + event.preventGridDefault(); + } +} +``` + +Check [more examples](website/routes/CellNavigation.lazy.tsx) + ###### `onSelectedCellChange?: Maybe<(args: CellSelectArgs) => void>;` Triggered when the selected cell is changed. @@ -211,20 +393,28 @@ Arguments: ###### `onScroll?: Maybe<(event: React.UIEvent) => void>` -###### `onColumnResize?: Maybe<(idx: number, width: number) => void>` +A function called when the grid is scrolled. + +###### `onColumnResize?: Maybe<(column: CalculatedColumn, width: number) => void>` + +A function called when column is resized. ###### `enableVirtualization?: Maybe` +**Default:** `true` + +This prop can be used to disable virtualization. + ###### `renderers?: Maybe>` This prop can be used to override the internal renderers. The prop accepts an object of type ```tsx interface Renderers { + renderCell?: Maybe<(key: Key, props: CellRendererProps) => ReactNode>; renderCheckbox?: Maybe<(props: RenderCheckboxProps) => ReactNode>; renderRow?: Maybe<(key: Key, props: RenderRowProps) => ReactNode>; renderSortStatus?: Maybe<(props: RenderSortStatusProps) => ReactNode>; - renderCell?: Maybe<(key: Key, props: CellRendererProps) => ReactNode>; noRowsFallback?: Maybe; } ``` @@ -249,9 +439,23 @@ function MyGrid() { :warning: To prevent all rows from being unmounted on re-renders, make sure to pass a static or memoized component to `renderRow`. -###### `rowClass?: Maybe<(row: R) => Maybe>` +###### `rowClass?: Maybe<(row: R, rowIdx: number) => Maybe>` -##### `direction?: Maybe<'ltr' | 'rtl'>` +A function to add a class on the row + +```tsx +import DataGrid from 'react-data-grid'; + +function MyGrid() { + return ; +} + +function rowClass(row: Row, rowIdx: number) { + return rowIdx % 2 === 0 ? 'even' : 'odd'; +} +``` + +###### `direction?: Maybe<'ltr' | 'rtl'>` This property sets the text direction of the grid, it defaults to `'ltr'` (left-to-right). Setting `direction` to `'rtl'` has the following effects: @@ -262,16 +466,54 @@ This property sets the text direction of the grid, it defaults to `'ltr'` (left- ###### `className?: string | undefined` +custom classname + ###### `style?: CSSProperties | undefined` +custom styles + ###### `'aria-label'?: string | undefined` +The label of the grid. We recommend providing a label using `aria-label` or `aria-labelledby` + ###### `'aria-labelledby'?: string | undefined` +The id of the element containing a label for the grid. We recommend providing a label using `aria-label` or `aria-labelledby` + +###### `'aria-description'?: string | undefined` + ###### `'aria-describedby'?: string | undefined` +If the grid has a caption or description, `aria-describedby` can be set on the grid element with a value referring to the element containing the description. + ###### `'data-testid'?: Maybe` +This prop can be used to add a testid for testing. We recommend using `role` and `name` to find the grid element + +```tsx +function MyGrid() { + return ; +} + +function MyGridTest() { + const grid = screen.getByRole('grid', { name: 'my-grid' }); +} +``` + +#### `` + +`TreeDataGrid` is component built on top of `DataGrid` to add row grouping. This implements the [Treegrid pattern](https://www.w3.org/WAI/ARIA/apg/patterns/treegrid/). At the moment `TreeDataGrid` does not support `onFill` and `isRowSelectionDisabled` props + +##### TreeDataGridProps + +###### `groupBy?: Maybe` + +###### `rowGrouper?: Maybe<(rows: readonly R[], columnKey: string) => Record>` + +###### `expandedGroupIds?: Maybe>` + +###### `onExpandedGroupIdsChange?: Maybe<(expandedGroupIds: Set) => void>` + #### `` ##### Props @@ -334,18 +576,73 @@ See [`RenderGroupCellProps`](#rendergroupcellprops) ### Hooks -#### `useRowSelection(): [boolean, (selectRowEvent: SelectRowEvent) => void]` +#### `useHeaderRowSelection(): { isIndeterminate, isRowSelected, onRowSelectionChange }` + +#### `useRowSelection(): { isRowSelectionDisabled, isRowSelected, onRowSelectionChange }` ### Other #### `SelectColumn: Column` -#### `SELECT_COLUMN_KEY = 'select-row'` +#### `SELECT_COLUMN_KEY = 'rdg-select-column'` ### Types #### `Column` +##### `name: string | ReactElement` + +The name of the column. By default it will be displayed in the header cell + +##### `key: string` + +A unique key to distinguish each column + +##### `width?: Maybe` + +**Default** `auto` + +Width can be any valid css grid column value. If not specified, it will be determined automatically based on grid width and specified widths of other columns. + +```tsx +width: 80; // pixels +width: '25%'; +width: 'max-content'; +width: 'minmax(100px, max-content)'; +``` + +`max-content` can be used to expand the column to show all the content. Note that the grid is only able to calculate column width for visible rows. + +##### `minWidth?: Maybe` + +**Default**: `50` pixels + +Sets the maximum width of a column. + +##### `maxWidth?: Maybe` + +Sets the maximum width of a column. + +##### `cellClass?: Maybe Maybe)>` + +A function to add a class on the row + +##### `headerCellClass?: Maybe` + +##### `summaryCellClass?: Maybe Maybe)>` + +##### `renderCell?: Maybe<(props: RenderCellProps) => ReactNode>` + +Render function used to render the content of cells + +##### `renderHeaderCell` + +Render function used to render the content of header cells + +##### `renderSummaryCell` + +Render function used to render the content of summary cells + #### `DataGridHandle` #### `RenderEditCellProps` diff --git a/eslint.config.js b/eslint.config.js index be52560a1d..82d8178c16 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -9,6 +9,7 @@ import reactHooks from 'eslint-plugin-react-hooks'; import reactHooksExtra from 'eslint-plugin-react-hooks-extra'; import sonarjs from 'eslint-plugin-sonarjs'; import testingLibrary from 'eslint-plugin-testing-library'; +import markdown from '@eslint/markdown'; export default [ { @@ -728,5 +729,23 @@ export default [ 'no-undef': 1, 'no-use-before-define': [1, { functions: false, classes: false, variables: false }] } + }, + + { + name: 'markdown', + files: ['**/*.md'], + plugins: { + markdown + }, + language: 'markdown/commonmark', + rules: { + 'markdown/fenced-code-language': 1, + 'markdown/heading-increment': 1, + 'markdown/no-duplicate-headings': 0, + 'markdown/no-empty-links': 1, + 'markdown/no-html': 0, + 'markdown/no-invalid-label-refs': 1, + 'markdown/no-missing-label-refs': 1 + } } ]; diff --git a/package.json b/package.json index 391d80fe22..555d76b87f 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "@babel/runtime": "^7.26.0", "@biomejs/biome": "1.9.4", "@eslint/compat": "^1.2.4", + "@eslint/markdown": "^6.2.1", "@faker-js/faker": "^9.3.0", "@ianvs/prettier-plugin-sort-imports": "^4.0.2", "@linaria/core": "^6.0.0", diff --git a/src/DataGrid.tsx b/src/DataGrid.tsx index dc6f6aeb58..1fff78dd17 100644 --- a/src/DataGrid.tsx +++ b/src/DataGrid.tsx @@ -85,7 +85,7 @@ interface EditCellState extends Position { readonly originalRow: R; } -type DefaultColumnOptions = Pick< +export type DefaultColumnOptions = Pick< Column, 'renderCell' | 'width' | 'minWidth' | 'maxWidth' | 'resizable' | 'sortable' | 'draggable' >; diff --git a/src/index.ts b/src/index.ts index d76283ea28..f016f98853 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,11 @@ import './style/layers.css'; -export { default, type DataGridProps, type DataGridHandle } from './DataGrid'; +export { + default, + type DataGridProps, + type DataGridHandle, + type DefaultColumnOptions +} from './DataGrid'; export { default as TreeDataGrid, type TreeDataGridProps } from './TreeDataGrid'; export { DataGridDefaultRenderersProvider } from './DataGridDefaultRenderersProvider'; export { default as Row } from './Row'; diff --git a/src/types.ts b/src/types.ts index 561bb651be..ebd01a9671 100644 --- a/src/types.ts +++ b/src/types.ts @@ -13,19 +13,25 @@ export interface Column { readonly name: string | ReactElement; /** A unique key to distinguish each column */ readonly key: string; - /** Column width. If not specified, it will be determined automatically based on grid width and specified widths of other columns */ + /** + * Column width. If not specified, it will be determined automatically based on grid width and specified widths of other columns + * @default 'auto' + */ readonly width?: Maybe; - /** Minimum column width in px. */ + /** + * Minimum column width in px + * @default '50px' + */ readonly minWidth?: Maybe; /** Maximum column width in px. */ readonly maxWidth?: Maybe; readonly cellClass?: Maybe Maybe)>; readonly headerCellClass?: Maybe; readonly summaryCellClass?: Maybe Maybe)>; - /** Render function used to render the content of the column's header cell */ - readonly renderHeaderCell?: Maybe<(props: RenderHeaderCellProps) => ReactNode>; /** Render function used to render the content of cells */ readonly renderCell?: Maybe<(props: RenderCellProps) => ReactNode>; + /** Render function used to render the content of the column's header cell */ + readonly renderHeaderCell?: Maybe<(props: RenderHeaderCellProps) => ReactNode>; /** Render function used to render the content of summary cells */ readonly renderSummaryCell?: Maybe< (props: RenderSummaryCellProps) => ReactNode @@ -310,10 +316,10 @@ export interface RenderCheckboxProps } export interface Renderers { + renderCell?: Maybe<(key: Key, props: CellRendererProps) => ReactNode>; renderCheckbox?: Maybe<(props: RenderCheckboxProps) => ReactNode>; renderRow?: Maybe<(key: Key, props: RenderRowProps) => ReactNode>; renderSortStatus?: Maybe<(props: RenderSortStatusProps) => ReactNode>; - renderCell?: Maybe<(key: Key, props: CellRendererProps) => ReactNode>; noRowsFallback?: Maybe; }