From de9c862ad77ef955ee7b57a113be4e832d2dca22 Mon Sep 17 00:00:00 2001 From: Afsal K Date: Thu, 6 Jun 2024 16:41:45 +0530 Subject: [PATCH] refactor(DataGrid): implement types for DataGrid component (#5257) * refactor(DataGrid): implement types for DataGrid component * refactor(DataGridContent): implement types for DataGridContent file * refactor(filterSummary): implement types * refactor(datagridContent): implement types * refactor(datagridHead): implement types * refactor(datagridBody): implement types * refactor(datagridEmptyBody): implement types * fix(datagridEmptyBody): empty state props * refactor(DatagridVirtualBody): implement types * refactor(datagridRefBody): implement types * refactor(DatagridSimpleBody): implement types * refactor(DatagridExpandedRow): implement types * refactor(DatagridHeaderRow): implement types * refactor(DatagridSlug): implement types * refactor(DatagridRow): implement types * refactor(DatagridSelectAll): implement types * refactor(DatagridSelectAllWithToggle): implement types * refactor(DatagridToolbar): implement types * refactor(DraggableEleemt): implement types * refactor(dataGrid): import carbon component props * refactor(DataGrid): reuse react-table types * refactor(DatagridHeaderRow): assign key value separately * refactor: change types according to react-table types * fix(datagrid): remove emptyState props * refactor: revert empty state props * refactor(datagrid): move index file to .ts * refactor: update type for state in all files * refactor: change row typw * chore: test issue * chore: revert test code * chore: remove condition * chore: remove condition * chore: revert condition * chore: state destructure * chore: test deployment issue 1 * chore: test deployment issue 1 * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * refactor: test deploy error * fix(DataGrid): resolve error in deployment * fix(DataGrid): resolve error on deployed version * chore(Datagrid): resolve PR comments * chore: dummy commit to rerun jobs * chore: remove unwanted line * refactor: change react-table types version * refactor: change react-table types version * chore: remove unwanted line refactor: change react-table types version refactor: change react-table types version * chore: dummy commit to rerun jobs chore: remove unwanted line refactor: change react-table types version refactor: change react-table types version chore: remove unwanted line refactor: change react-table types version refactor: change react-table types version * chore: dummy commit to rerun jobs chore: remove unwanted line refactor: change react-table types version refactor: change react-table types version chore: remove unwanted line refactor: change react-table types version refactor: change react-table types version chore: dummy commit to rerun jobs chore: remove unwanted line refactor: change react-table types version refactor: change react-table types version chore: remove unwanted line refactor: change react-table types version refactor: change react-table types version * chore(release): publish [skip ci] - @carbon/ibm-cloud-cognitive-core@2.18.3 - @carbon/ibm-products@2.41.0 - @carbon/ibm-products-styles@2.38.0 * chore(Datagrid): resolve PR comments * fix(CreateTearsheet): add focus trap behavior (#5329) * test(ExpressiveCard): add @avt test for default state (#5393) * test(Toolbar): add default state AVT test (#5395) * fix(Coachmark): ssr issues with `instanceOf(HTMLElement)` (#5391) * fix(Coachmark): ssr issues with htmlelement * chore: remove unnecessary export * Add .whitesource configuration file (#5323) Co-authored-by: ibm-mend-app[bot] <142626574+ibm-mend-app[bot]@users.noreply.github.com> Co-authored-by: Jeff Chew * refactor(TagOverflowModal): add Typescript types to TagOverflowModal (#5311) * fix(Datagrid): add disable cell support (#5385) * test(ProductiveCard): add default state AVT test (#5394) * feat(FeatureFlags): add new mechanism for feature flagging using `@carbon/feature-flags` (#5204) * feat(FeatureFlags): add feature flag support using carbon package * chore: import feature flags and update lock * chore: remove console log * feat: use new feature flag system and add mdx docs * chore: add annotation component to example story * fix: remove utility hook from portal target hook * chore: rename feature-flags file * chore: remove console log * chore: add feature flag component to editable cell stories * fix: import feature flags file * fix: import feature flags in jest setup * fix: update tests * chore: remove old generated feature flags * chore: import feature flags * fix: add feature flags file as side effect * chore: add test file * chore(feature-flags): rename to match carbon naming patterns chore: dummy commit to rerun jobs chore: remove unwanted line refactor: change react-table types version refactor: change react-table types version chore: remove unwanted line refactor: change react-table types version refactor: change react-table types version chore: dummy commit to rerun jobs chore: remove unwanted line refactor: change react-table types version refactor: change react-table types version chore: remove unwanted line refactor: change react-table types version refactor: change react-table types version chore: dummy commit to rerun jobs chore: remove unwanted line refactor: change react-table types version refactor: change react-table types version chore: remove unwanted line refactor: change react-table types version refactor: change react-table types version chore: dummy commit to rerun jobs chore: remove unwanted line refactor: change react-table types version refactor: change react-table types version chore: remove unwanted line refactor: change react-table types version refactor: change react-table types version * chore: resolve merge conflict * refactor: resolve minor issues * test: resolve test issue --------- Co-authored-by: github-merge-queue <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Gallo Co-authored-by: andrew Co-authored-by: Ignacio Becerra Co-authored-by: ibm-mend-app[bot] <142626574+ibm-mend-app[bot]@users.noreply.github.com> Co-authored-by: Jeff Chew Co-authored-by: Anamika T S <47971732+anamikaanu96@users.noreply.github.com> Co-authored-by: Austin --- packages/ibm-products/package.json | 1 + .../DataSpreadsheet/DataSpreadsheet.tsx | 22 +- .../DataSpreadsheet/DataSpreadsheetBody.tsx | 23 +- .../DataSpreadsheet/DataSpreadsheetHeader.tsx | 7 +- .../components/DataSpreadsheet/types/index.ts | 6 +- .../Datagrid/{Datagrid.js => Datagrid.tsx} | 35 ++- .../{DatagridBody.js => DatagridBody.tsx} | 3 +- ...DatagridContent.js => DatagridContent.tsx} | 93 +++--- ...gridEmptyBody.js => DatagridEmptyBody.tsx} | 9 +- ...ExpandedRow.js => DatagridExpandedRow.tsx} | 12 +- .../{DatagridHead.js => DatagridHead.tsx} | 6 +- ...gridHeaderRow.js => DatagridHeaderRow.tsx} | 137 +++++---- ...DatagridRefBody.js => DatagridRefBody.tsx} | 7 +- .../{DatagridRow.js => DatagridRow.tsx} | 18 +- ...gridSelectAll.js => DatagridSelectAll.tsx} | 15 +- ...gle.js => DatagridSelectAllWithToggle.tsx} | 25 +- ...idSimpleBody.js => DatagridSimpleBody.tsx} | 5 +- ...DatagridToolbar.js => DatagridToolbar.tsx} | 41 ++- ...VirtualBody.js => DatagridVirtualBody.tsx} | 56 ++-- ...aggableElement.js => DraggableElement.tsx} | 17 +- .../Datagrid/addons/Filtering/FilterPanel.js | 2 +- .../Datagrid/addons/Slug/DatagridSlug.js | 27 -- .../Datagrid/addons/Slug/DatagridSlug.tsx | 43 +++ .../Datagrid/Datagrid/{index.js => index.ts} | 0 .../src/components/Datagrid/types/index.ts | 281 ++++++++++++++++++ .../src/components/Datagrid/useSelectRows.js | 5 +- .../{FilterSummary.js => FilterSummary.tsx} | 57 +++- .../src/custom-typings/index.d.ts | 3 + yarn.lock | 10 + 29 files changed, 720 insertions(+), 246 deletions(-) rename packages/ibm-products/src/components/Datagrid/Datagrid/{Datagrid.js => Datagrid.tsx} (80%) rename packages/ibm-products/src/components/Datagrid/Datagrid/{DatagridBody.js => DatagridBody.tsx} (90%) rename packages/ibm-products/src/components/Datagrid/Datagrid/{DatagridContent.js => DatagridContent.tsx} (83%) rename packages/ibm-products/src/components/Datagrid/Datagrid/{DatagridEmptyBody.js => DatagridEmptyBody.tsx} (89%) rename packages/ibm-products/src/components/Datagrid/Datagrid/{DatagridExpandedRow.js => DatagridExpandedRow.tsx} (79%) rename packages/ibm-products/src/components/Datagrid/Datagrid/{DatagridHead.js => DatagridHead.tsx} (75%) rename packages/ibm-products/src/components/Datagrid/Datagrid/{DatagridHeaderRow.js => DatagridHeaderRow.tsx} (67%) rename packages/ibm-products/src/components/Datagrid/Datagrid/{DatagridRefBody.js => DatagridRefBody.tsx} (82%) rename packages/ibm-products/src/components/Datagrid/Datagrid/{DatagridRow.js => DatagridRow.tsx} (92%) rename packages/ibm-products/src/components/Datagrid/Datagrid/{DatagridSelectAll.js => DatagridSelectAll.tsx} (85%) rename packages/ibm-products/src/components/Datagrid/Datagrid/{DatagridSelectAllWithToggle.js => DatagridSelectAllWithToggle.tsx} (84%) rename packages/ibm-products/src/components/Datagrid/Datagrid/{DatagridSimpleBody.js => DatagridSimpleBody.tsx} (83%) rename packages/ibm-products/src/components/Datagrid/Datagrid/{DatagridToolbar.js => DatagridToolbar.tsx} (86%) rename packages/ibm-products/src/components/Datagrid/Datagrid/{DatagridVirtualBody.js => DatagridVirtualBody.tsx} (65%) rename packages/ibm-products/src/components/Datagrid/Datagrid/{DraggableElement.js => DraggableElement.tsx} (85%) delete mode 100644 packages/ibm-products/src/components/Datagrid/Datagrid/addons/Slug/DatagridSlug.js create mode 100644 packages/ibm-products/src/components/Datagrid/Datagrid/addons/Slug/DatagridSlug.tsx rename packages/ibm-products/src/components/Datagrid/Datagrid/{index.js => index.ts} (100%) create mode 100644 packages/ibm-products/src/components/Datagrid/types/index.ts rename packages/ibm-products/src/components/FilterSummary/{FilterSummary.js => FilterSummary.tsx} (78%) diff --git a/packages/ibm-products/package.json b/packages/ibm-products/package.json index 948d206e60..2e4e65a750 100644 --- a/packages/ibm-products/package.json +++ b/packages/ibm-products/package.json @@ -71,6 +71,7 @@ "@rollup/plugin-commonjs": "^25.0.0", "@rollup/plugin-node-resolve": "^15.0.0", "@rollup/plugin-typescript": "^11.0.0", + "@types/react-table": "^7.7.20", "babel-plugin-dev-expression": "^0.2.3", "babel-preset-ibm-cloud-cognitive": "^0.14.40", "chalk": "^4.1.2", diff --git a/packages/ibm-products/src/components/DataSpreadsheet/DataSpreadsheet.tsx b/packages/ibm-products/src/components/DataSpreadsheet/DataSpreadsheet.tsx index bb50b7124b..5cee63eac3 100644 --- a/packages/ibm-products/src/components/DataSpreadsheet/DataSpreadsheet.tsx +++ b/packages/ibm-products/src/components/DataSpreadsheet/DataSpreadsheet.tsx @@ -16,7 +16,14 @@ import React, { MutableRefObject, LegacyRef, } from 'react'; -import { useBlockLayout, useTable, useColumnOrder } from 'react-table'; +import { + useBlockLayout, + useTable, + useColumnOrder, + Column, + UseColumnOrderInstanceProps, + TableInstance, +} from 'react-table'; // Other standard imports. import PropTypes from 'prop-types'; @@ -48,7 +55,7 @@ import { removeCellSelections } from './utils/removeCellSelections'; import { selectAllCells } from './utils/selectAllCells'; import { handleEditSubmit } from './utils/handleEditSubmit'; import { handleKeyPress } from './utils/commonEventHandlers'; -import { ActiveCellCoordinates, Column, PrevState, Size, Theme } from './types'; +import { ActiveCellCoordinates, PrevState, Size, Theme } from './types'; // The block part of our conventional BEM class names (blockClass__E--M). const blockClass = `${pkg.prefix}--data-spreadsheet`; @@ -79,7 +86,7 @@ interface DataSpreadsheetProps { /** * The data that will build the column headers */ - columns?: readonly Column[]; + columns?: readonly Column[]; /** * The spreadsheet data that will be rendered in the body of the spreadsheet component @@ -186,7 +193,7 @@ export let DataSpreadsheet = React.forwardRef( }) || {}; const cellSizeValue = getCellSize(cellSize); const cellEditorRef = useRef(); - const [activeCellContent, setActiveCellContent] = useState(null); + const [activeCellContent, setActiveCellContent] = useState(); const activeCellRef = useRef(); const cellEditorRulerRef = useRef(); const defaultColumn = useMemo( @@ -221,7 +228,7 @@ export let DataSpreadsheet = React.forwardRef( }, useBlockLayout, useColumnOrder - ); + ) as UseColumnOrderInstanceProps & TableInstance; // Update the spreadsheet data after editing a cell const updateData = useCallback( @@ -268,7 +275,8 @@ export let DataSpreadsheet = React.forwardRef( prevCoords?.column !== activeCellCoordinates?.column) && isEditing ) { - const cellProps = rows[prevCoords?.row].cells[prevCoords?.column]; + const cellProps = + rows[Number(prevCoords?.row)].cells[Number(prevCoords?.column)]; removeCellEditor(); updateData(prevCoords?.row, cellProps.column.id, undefined); if (cellEditorRulerRef?.current) { @@ -803,7 +811,7 @@ export let DataSpreadsheet = React.forwardRef( [`${blockClass}__${theme}`]: theme === 'dark', } )} - ref={spreadsheetRef} + ref={spreadsheetRef as MutableRefObject} role="grid" tabIndex={0} aria-rowcount={rows?.length || 0} diff --git a/packages/ibm-products/src/components/DataSpreadsheet/DataSpreadsheetBody.tsx b/packages/ibm-products/src/components/DataSpreadsheet/DataSpreadsheetBody.tsx index e237136d55..1261203f27 100644 --- a/packages/ibm-products/src/components/DataSpreadsheet/DataSpreadsheetBody.tsx +++ b/packages/ibm-products/src/components/DataSpreadsheet/DataSpreadsheetBody.tsx @@ -38,7 +38,13 @@ import { handleRowHeaderClick, } from './utils/commonEventHandlers'; import { prepareProps } from '../../global/js/utils/props-helper'; -import { ActiveCellCoordinates, Column, PrevState } from './types'; +import { ActiveCellCoordinates, PrevState, SpreadsheetColumn } from './types'; +import { + Column, + IdType, + TableBodyPropGetter, + TableBodyProps, +} from 'react-table'; const blockClass = `${pkg.prefix}--data-spreadsheet`; @@ -60,7 +66,7 @@ interface DataSpreadsheetBodyProps { /** * All of the spreadsheet columns */ - columns?: readonly Column[]; + columns?: readonly Column[]; /** * This represents the id of the current cell selection area @@ -70,7 +76,7 @@ interface DataSpreadsheetBodyProps { /** * Default spreadsheet sizing values */ - defaultColumn?: Column; + defaultColumn?: SpreadsheetColumn; /** * Sets the number of empty rows to be created when there is no data provided @@ -80,7 +86,7 @@ interface DataSpreadsheetBodyProps { /** * Function to set table body prop values */ - getTableBodyProps?: () => { data }; + getTableBodyProps: (propGetter?: TableBodyPropGetter) => TableBodyProps; /** * Headers provided from useTable hook @@ -152,7 +158,11 @@ interface DataSpreadsheetBodyProps { /** * Setter fn for column ordering, provided from react-table */ - setColumnOrder?: () => void; + setColumnOrder?: ( + updater: + | ((columnOrder: Array>) => Array>) + | Array> + ) => void; /** * Setter fn for containerHasFocus state value @@ -193,7 +203,7 @@ interface DataSpreadsheetBodyProps { /** * Prop from react-table used to reorder columns */ - visibleColumns?: []; + visibleColumns?: Column[]; } export const DataSpreadsheetBody = forwardRef( @@ -797,6 +807,7 @@ DataSpreadsheetBody.propTypes = { /** * Function to set table body prop values */ + /**@ts-ignore */ getTableBodyProps: PropTypes.func, /** diff --git a/packages/ibm-products/src/components/DataSpreadsheet/DataSpreadsheetHeader.tsx b/packages/ibm-products/src/components/DataSpreadsheet/DataSpreadsheetHeader.tsx index e4d293f14b..de9c9ef481 100644 --- a/packages/ibm-products/src/components/DataSpreadsheet/DataSpreadsheetHeader.tsx +++ b/packages/ibm-products/src/components/DataSpreadsheet/DataSpreadsheetHeader.tsx @@ -29,11 +29,12 @@ import { checkForHoldingKey } from './utils/checkForHoldingKey'; import { prepareProps } from '../../global/js/utils/props-helper'; import { ActiveCellCoordinates, - Column, ItemType, PrevState, Size, + SpreadsheetColumn, } from './types'; +import { Column } from 'react-table'; const blockClass = `${pkg.prefix}--data-spreadsheet`; @@ -61,7 +62,7 @@ interface DataSpreadsheetHeaderProps { /** * Default spreadsheet sizing values */ - defaultColumn?: Column; + defaultColumn?: SpreadsheetColumn; /** * Whether or not a click/hold is active on a header cell @@ -134,7 +135,7 @@ interface DataSpreadsheetHeaderProps { /** * Array of visible columns provided by react-table useTable hook */ - visibleColumns?: []; + visibleColumns?: Column[]; } export const DataSpreadsheetHeader = forwardRef( diff --git a/packages/ibm-products/src/components/DataSpreadsheet/types/index.ts b/packages/ibm-products/src/components/DataSpreadsheet/types/index.ts index c6ee938021..b02c93dc2f 100644 --- a/packages/ibm-products/src/components/DataSpreadsheet/types/index.ts +++ b/packages/ibm-products/src/components/DataSpreadsheet/types/index.ts @@ -1,9 +1,7 @@ export type Size = 'xs' | 'sm' | 'md' | 'lg'; export type Theme = 'light' | 'dark'; -export interface Column { - Header?: string; - accessor?: string | (() => void); - Cell?: () => void; // optional cell formatter + +export interface SpreadsheetColumn { rowHeight?: number; rowHeaderWidth?: number; width?: number; diff --git a/packages/ibm-products/src/components/Datagrid/Datagrid/Datagrid.js b/packages/ibm-products/src/components/Datagrid/Datagrid/Datagrid.tsx similarity index 80% rename from packages/ibm-products/src/components/Datagrid/Datagrid/Datagrid.js rename to packages/ibm-products/src/components/Datagrid/Datagrid/Datagrid.tsx index 145695a3fd..b13d4d2f0c 100644 --- a/packages/ibm-products/src/components/Datagrid/Datagrid/Datagrid.js +++ b/packages/ibm-products/src/components/Datagrid/Datagrid/Datagrid.tsx @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import React from 'react'; +import React, { ForwardedRef } from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; @@ -15,20 +15,40 @@ import pconsole from '../../../global/js/utils/pconsole'; import { InlineEditProvider } from './addons/InlineEdit/InlineEditContext'; import { DatagridContent } from './DatagridContent'; import { FilterProvider } from './addons/Filtering/FilterProvider'; +import { DataGridState, DatagridRow } from '../types'; const blockClass = `${pkg.prefix}--datagrid`; const componentName = 'Datagrid'; +export interface DatagridProps { + /** + * Specify a label to be read by screen readers on the container node + * 'aria-label' of the TableToolbar component. + */ + ariaToolbarLabel?: string; + /** + * The data grid state, much of it being supplied by the useDatagrid hook + */ + datagridState: DataGridState; + /** + * Table title + */ + title?: string; +} + /** * The `Datagrid` component is an extension of Carbon's DataTable component. At the most basic level, the `Datagrid` component takes in columns and rows and renders a data table. There is a set of data table extensions which this component provides support for, these can be found [here](https://pages.github.ibm.com/cdai-design/pal/components/data-table/overview/). This component is data driven and allows you to choose what pieces will be included based on the hooks/plugins that are provided. */ export let Datagrid = React.forwardRef( - ({ datagridState, title, ariaToolbarLabel, ...rest }, ref) => { + ( + { datagridState, title, ariaToolbarLabel, ...rest }: DatagridProps, + ref: ForwardedRef + ) => { if (!datagridState) { pconsole.warn( 'Datagrid was not passed datagridState which is required to render this component.' ); - return null; + return; } const { @@ -38,11 +58,11 @@ export let Datagrid = React.forwardRef( tableId, filterProps, className, - state: { filters }, + state, } = datagridState; - const rows = - (DatagridPagination && datagridState.page) || datagridState.rows; + const rows = ((DatagridPagination && datagridState.page) || + datagridState.rows) as DatagridRow[]; const props = { title, @@ -51,7 +71,7 @@ export let Datagrid = React.forwardRef( }; return ( - +
{ +const DatagridBody = (datagridState: DataGridState) => { const { isFetching, rows = [], diff --git a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridContent.js b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridContent.tsx similarity index 83% rename from packages/ibm-products/src/components/Datagrid/Datagrid/DatagridContent.js rename to packages/ibm-products/src/components/Datagrid/Datagrid/DatagridContent.tsx index de7f6b9aa2..bccde8bc21 100644 --- a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridContent.js +++ b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridContent.tsx @@ -1,15 +1,14 @@ -/** - * Copyright IBM Corp. 2022, 2024 - * - * This source code is licensed under the Apache-2.0 license found in the - * LICENSE file in the root directory of this source tree. - */ +// /** +// * Copyright IBM Corp. 2022, 2024 +// * +// * This source code is licensed under the Apache-2.0 license found in the +// * LICENSE file in the root directory of this source tree. +// */ import { FilterContext, FilterPanel } from './addons/Filtering'; -import React, { useContext, useEffect, useRef } from 'react'; +import React, { useContext, ForwardedRef, useRef, useEffect } from 'react'; import { Table, TableContainer } from '@carbon/react'; import { carbon, pkg } from '../../../settings'; - import { CLEAR_FILTERS, CLEAR_SINGLE_FILTER, @@ -28,12 +27,23 @@ import { useClickOutside } from '../../../global/js/hooks'; import { useMultipleKeyTracking } from '../../DataSpreadsheet/hooks'; import { useSubscribeToEventEmitter } from './addons/Filtering/hooks'; import { clearSingleFilter } from './addons/Filtering/FilterProvider'; +import { DataGridState, DatagridRow } from '../types'; import { useFeatureFlag } from '../../FeatureFlags'; const blockClass = `${pkg.prefix}--datagrid`; const gcClass = `${blockClass}__grid-container`; -export const DatagridContent = ({ datagridState, title, ariaToolbarLabel }) => { +interface DatagridContentProps { + ariaToolbarLabel?: string; + datagridState: DataGridState; + title?: string; +} + +export const DatagridContent = ({ + datagridState, + ariaToolbarLabel, + title, +}: DatagridContentProps) => { const { state: inlineEditState, dispatch } = useContext(InlineEditContext); const { filterTags, EventEmitter, panelOpen } = useContext(FilterContext); const { activeCellId, gridActive, editId, featureFlags } = inlineEditState; @@ -61,11 +71,12 @@ export const DatagridContent = ({ datagridState, title, ariaToolbarLabel }) => { page, rows, } = datagridState; + const { columnResizing } = state; - const contentRows = (DatagridPagination && page) || rows; - const gridAreaRef = useRef(); - const multiKeyTrackingRef = useRef(); + const contentRows = ((DatagridPagination && page) || rows) as DatagridRow[]; + const gridAreaRef: ForwardedRef = useRef(null); + const multiKeyTrackingRef: ForwardedRef = useRef(null); const enableEditableCell = useFeatureFlag('enable-datagrid-useEditableCell'); const enableInlineEdit = useFeatureFlag('enable-datagrid-useInlineEdit'); @@ -116,7 +127,7 @@ export const DatagridContent = ({ datagridState, title, ariaToolbarLabel }) => { return ( <> { [`${blockClass}__table-is-resizing`]: typeof columnResizing?.isResizingColumn === 'string', }, - getTableProps()?.className + getTableProps?.().className )} - role={withInlineEdit ? 'grid' : undefined} - tabIndex={withInlineEdit ? 0 : -1} - onKeyDown={ - /* istanbul ignore next */ - withInlineEdit && - ((event) => - handleGridKeyPress({ - event, - dispatch, - instance: datagridState, - keysPressedList, - state: inlineEditState, - usingMac, - ref: multiKeyTrackingRef, - })) - } - onFocus={ - withInlineEdit && (() => handleGridFocus(inlineEditState, dispatch)) - } - title={title} + {...{ + role: withInlineEdit ? 'grid' : undefined, + tabIndex: withInlineEdit ? 0 : -1, + onKeyDown: + withInlineEdit && + ((event) => + handleGridKeyPress({ + event, + dispatch, + instance: datagridState, + keysPressedList, + state: inlineEditState, + usingMac, + ref: multiKeyTrackingRef, + })), + onFocus: + withInlineEdit && + (() => handleGridFocus(inlineEditState, dispatch)), + title, + }} > {(!withVirtualScroll || (withVirtualScroll && !isFetching && !contentRows.length)) && ( @@ -174,16 +185,18 @@ export const DatagridContent = ({ datagridState, title, ariaToolbarLabel }) => { if (!withInlineEdit) { return; } - const gridElement = document.querySelector(`#${tableId}`); + const gridElement: HTMLElement | null = document.querySelector( + `#${tableId}` + ); const tableHeader = gridElement?.querySelector( `.${carbon.prefix}--data-table-header` ); - gridElement.style.setProperty( + gridElement?.style?.setProperty( `--${blockClass}--grid-width`, - px(totalColumnsWidth + 32) + px((totalColumnsWidth || 0) + 32) ); if (gridActive) { - gridElement.style.setProperty( + gridElement?.style.setProperty( `--${blockClass}--grid-header-height`, px(tableHeader?.clientHeight || 0) ); @@ -200,7 +213,7 @@ export const DatagridContent = ({ datagridState, title, ariaToolbarLabel }) => { className={`${blockClass}__filter-summary`} filters={filterTags} clearFilters={() => EventEmitter.dispatch(CLEAR_FILTERS)} - renderLabel={filterProps.renderLabel} + renderLabel={filterProps?.renderLabel} overflowType="tag" /> ); @@ -239,7 +252,7 @@ export const DatagridContent = ({ datagridState, title, ariaToolbarLabel }) => { > {filterProps?.variation === 'panel' && ( { +const DatagridEmptyBody = (datagridState: DataGridState) => { const { getTableBodyProps, headers, @@ -44,12 +45,12 @@ const DatagridEmptyBody = (datagridState) => { return ( {validEmptyStates.includes(emptyStateType) ? ( @@ -65,7 +66,7 @@ const DatagridEmptyBody = (datagridState) => { )} ) : ( - + )} diff --git a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridExpandedRow.js b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridExpandedRow.tsx similarity index 79% rename from packages/ibm-products/src/components/Datagrid/Datagrid/DatagridExpandedRow.js rename to packages/ibm-products/src/components/Datagrid/Datagrid/DatagridExpandedRow.tsx index d77ae65906..c44f4c74c2 100644 --- a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridExpandedRow.js +++ b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridExpandedRow.tsx @@ -5,19 +5,21 @@ * LICENSE file in the root directory of this source tree. */ -import React, { isValidElement } from 'react'; +import React, { JSXElementConstructor, isValidElement } from 'react'; import { pkg } from '../../../settings'; import cx from 'classnames'; +import { DataGridState } from '../types'; const blockClass = `${pkg.prefix}--datagrid`; // eslint-disable-next-line react/prop-types const DatagridExpandedRow = - (ExpandedRowContentComponent) => (datagridState) => { + (ExpandedRowContentComponent: JSXElementConstructor) => + (datagridState: DataGridState) => { const { row } = datagridState; const { expandedContentHeight } = row; - const toggleParentHoverClass = (event, eventType) => { + const toggleParentHoverClass = (event, eventType = '') => { /* istanbul ignore else */ if (event?.target?.closest('tr').previousElementSibling) { const parentNode = event?.target?.closest('tr').previousElementSibling; @@ -29,6 +31,8 @@ const DatagridExpandedRow = } }; + const { key, ..._state } = datagridState; + return ( - + diff --git a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridHead.js b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridHead.tsx similarity index 75% rename from packages/ibm-products/src/components/Datagrid/Datagrid/DatagridHead.js rename to packages/ibm-products/src/components/Datagrid/Datagrid/DatagridHead.tsx index af1f1db581..51bd46f56e 100644 --- a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridHead.js +++ b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridHead.tsx @@ -7,14 +7,16 @@ import React from 'react'; import { TableHead } from '@carbon/react'; +import { DataGridState } from '../types'; -const DatagridHead = (datagridState) => { +const DatagridHead = (datagridState: DataGridState) => { const { headerGroups = [], headRef, HeaderRow } = datagridState; + return ( {headerGroups.map((headerGroup) => // doesn't support header grouping. - HeaderRow(datagridState, headRef, headerGroup) + HeaderRow?.(datagridState, headRef, headerGroup) )} ); diff --git a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridHeaderRow.js b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridHeaderRow.tsx similarity index 67% rename from packages/ibm-products/src/components/Datagrid/Datagrid/DatagridHeaderRow.js rename to packages/ibm-products/src/components/Datagrid/Datagrid/DatagridHeaderRow.tsx index addc412b0b..ebbe8857bb 100644 --- a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridHeaderRow.js +++ b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridHeaderRow.tsx @@ -6,7 +6,12 @@ * LICENSE file in the root directory of this source tree. */ -import React, { useState, useEffect, isValidElement } from 'react'; +import React, { + useState, + useEffect, + isValidElement, + MutableRefObject, +} from 'react'; import cx from 'classnames'; import { TableHeader, TableRow } from '@carbon/react'; import { px } from '@carbon/layout'; @@ -19,11 +24,23 @@ import { import { getNodeTextContent } from '../../../global/js/utils/getNodeTextContent'; import { DatagridSlug } from './addons/Slug/DatagridSlug'; import { useInitialColumnSort } from '../useInitialColumnSort'; +import { + DataGridHeader, + DataGridHeaderGroup, + DataGridState, + DataGridTableInstance, + DatagridTableHooks, + ResizeHeaderProps, +} from '../types'; const blockClass = `${pkg.prefix}--datagrid`; -const getAccessibilityProps = (header) => { - const props = {}; +interface PropsType { + title?: string; +} + +const getAccessibilityProps = (header: DataGridHeader) => { + const props: PropsType = {}; const title = getNodeTextContent(header.Header); if (title) { props.title = title; @@ -46,27 +63,29 @@ const ResizeHeader = ({ onColResizeEnd, resizerAriaLabel, isFetching, -}) => { - // eslint-disable-next-line no-unused-vars - const { role, ...headerProps } = resizerProps; +}: ResizeHeaderProps) => { + const { ...headerProps } = resizerProps; const mouseDownHandler = (evt) => { - handleOnMouseDownResize(evt, resizerProps); + handleOnMouseDownResize?.(evt, resizerProps); }; const mouseUpHandler = () => { - handleColumnResizeEndEvent(dispatch, onColResizeEnd, header.id, true); + handleColumnResizeEndEvent(dispatch, onColResizeEnd, header?.id, true); }; const keyDownHandler = (evt) => { const { key } = evt; if (key === 'ArrowLeft' || key === 'ArrowRight') { - const originalColMinWidth = originalCol.minWidth || 90; + const originalColMinWidth = originalCol?.minWidth || 90; const currentColumnWidth = - columnWidths[header.id] || - (datagridState.isTableSortable && - originalCol.width < originalColMinWidth + (header?.id && columnWidths?.[header?.id]) || + (datagridState?.isTableSortable && + Number(originalCol?.width) < originalColMinWidth ? originalColMinWidth - : originalCol.width); + : originalCol?.width); if (key === 'ArrowLeft') { - if (currentColumnWidth - incrementAmount > Math.max(minWidth, 50)) { + if ( + currentColumnWidth - incrementAmount > + Math.max(Number(minWidth), 50) + ) { const newWidth = currentColumnWidth - incrementAmount; handleColumnResizingEvent(dispatch, header, newWidth, true); } @@ -78,7 +97,7 @@ const ResizeHeader = ({ } }; const keyUpHandler = () => { - handleColumnResizeEndEvent(dispatch, onColResizeEnd, header.id, true); + handleColumnResizeEndEvent(dispatch, onColResizeEnd, header?.id, true); }; return ( <> @@ -90,7 +109,7 @@ const ResizeHeader = ({ onKeyUp={keyUpHandler} className={`${blockClass}__col-resizer-range`} type="range" - defaultValue={originalCol.width} + defaultValue={originalCol?.width} aria-label={resizerAriaLabel || 'Resize column'} disabled={isFetching} /> @@ -99,49 +118,60 @@ const ResizeHeader = ({ ); }; -const HeaderRow = (datagridState, headRef, headerGroup) => { +const HeaderRow = ( + datagridState: DataGridState, + headRef: MutableRefObject, + headerGroup: DataGridHeaderGroup +) => { const { resizerAriaLabel, isTableSortable, rows, isFetching } = datagridState; useInitialColumnSort(datagridState); // Used to measure the height of the table and uses that value // to display a vertical line to indicate the column you are resizing useEffect(() => { const { tableId } = datagridState; - const gridElement = document.querySelector(`#${tableId}`); - const tableElement = gridElement.querySelector('table'); - const headerRowElement = document.querySelector( - `#${tableId} .${blockClass}__head` + const gridElement: HTMLDivElement | null = document.querySelector( + `#${tableId}` ); - const hasHorizontalScrollbar = - tableElement.scrollWidth > tableElement.clientWidth; - const scrollBuffer = hasHorizontalScrollbar ? 18 : 2; - const tableToolbar = gridElement.querySelector( - `.${blockClass}__table-toolbar` + const tableElement = gridElement?.querySelector('table'); + const headerRowElement: HTMLDivElement | null = document.querySelector( + `#${tableId} .${blockClass}__head` ); + let scrollBuffer = 2; + if (tableElement) { + const hasHorizontalScrollbar = + tableElement?.scrollWidth > tableElement?.clientWidth; + + if (hasHorizontalScrollbar) { + scrollBuffer = 18; + } + } + const tableToolbar: HTMLDivElement | null = + gridElement?.querySelector(`.${blockClass}__table-toolbar`) || null; const tableToolbarHeight = tableToolbar?.offsetHeight || 0; const setCustomValues = ({ rowHeight, gridHeight }) => { - headerRowElement.style.setProperty( + headerRowElement?.style.setProperty( `--${blockClass}--row-height`, px(rowHeight) ); - headerRowElement.style.setProperty( + headerRowElement?.style.setProperty( `--${blockClass}--grid-height`, px(gridHeight - scrollBuffer - tableToolbarHeight) ); - headerRowElement.style.setProperty( + headerRowElement?.style.setProperty( `--${blockClass}--header-height`, px(headerRowElement.offsetHeight) ); }; setCustomValues({ - gridHeight: gridElement.offsetHeight, - rowHeight: headerRowElement.clientHeight, + gridHeight: gridElement?.offsetHeight, + rowHeight: headerRowElement?.clientHeight, }); }, [datagridState.rowSize, datagridState.tableId, datagridState]); const [incrementAmount] = useState(2); const handleOnMouseDownResize = (event, resizeProps) => { - const { onMouseDown } = { ...resizeProps }; + const { onMouseDown = () => {} } = { ...resizeProps }; // When event.button is 2, that is a right click // and we do not want to resize if (event.button === 2 || event.ctrlKey) { @@ -151,12 +181,8 @@ const HeaderRow = (datagridState, headRef, headerGroup) => { onMouseDown?.(event); }; - const { - className: headerGroupClassName, - // eslint-disable-next-line no-unused-vars - role, - ...headerGroupProps - } = headerGroup.getHeaderGroupProps(); + const { className: headerGroupClassName, ...headerGroupProps } = + headerGroup.getHeaderGroupProps(); const renderSlug = (slug) => { if (isTableSortable) { @@ -166,17 +192,20 @@ const HeaderRow = (datagridState, headRef, headerGroup) => { }; const foundAIRow = rows.some((r) => isValidElement(r?.original?.slug)); - + const { key, ...rowProps } = headerGroupProps; return ( {foundAIRow ? { getTableBodyProps().className )} > - {rows.map((row) => { + {rows?.map((row) => { prepareRow(row); const { key } = row.getRowProps(); - return row.RowRenderer({ ...datagridState, row, key }); + return row?.RowRenderer?.({ ...datagridState, row, key }); })} ); diff --git a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridRow.js b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridRow.tsx similarity index 92% rename from packages/ibm-products/src/components/Datagrid/Datagrid/DatagridRow.js rename to packages/ibm-products/src/components/Datagrid/Datagrid/DatagridRow.tsx index 07894929d4..7a42a7b5b3 100644 --- a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridRow.js +++ b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridRow.tsx @@ -12,6 +12,7 @@ import { selectionColumnId } from '../common-column-ids'; import cx from 'classnames'; import { pkg, carbon } from '../../../settings'; import { DatagridSlug } from './addons/Slug/DatagridSlug'; +import { DataGridState } from '../types'; const blockClass = `${pkg.prefix}--datagrid`; @@ -24,7 +25,7 @@ const rowHeights = { }; // eslint-disable-next-line react/prop-types -const DatagridRow = (datagridState) => { +const DatagridRow = (datagridState: DataGridState) => { const { row, rows, @@ -55,7 +56,9 @@ const DatagridRow = (datagridState) => { return; } const subRowCount = getVisibleNestedRowCount(row); - const totalNestedRowIndicatorHeight = px(subRowCount * rowHeights[rowSize]); + const totalNestedRowIndicatorHeight = px( + subRowCount * rowHeights[Number(rowSize)] + ); const hoverRow = event.target.closest( `.${blockClass}__carbon-row-expanded` ); @@ -97,7 +100,7 @@ const DatagridRow = (datagridState) => { const handleMouseLeave = (event) => { if (withMouseHover) { - setMouseOverRowIndex(null); + setMouseOverRowIndex?.(null); } const hoverRow = event.target.closest( `.${blockClass}__carbon-row-expanded` @@ -126,8 +129,7 @@ const DatagridRow = (datagridState) => { return {}; }; - // eslint-disable-next-line no-unused-vars - const { role, className, ...rowProps } = row.getRowProps(); + const { className, ...rowProps } = row.getRowProps(); const foundAIRow = rows.some((r) => isValidElement(r?.original?.slug)); const rowClassNames = cx(`${blockClass}__carbon-row`, { @@ -166,7 +168,7 @@ const DatagridRow = (datagridState) => { {row.cells.map((cell, index) => { const cellProps = cell.getCellProps(); // eslint-disable-next-line no-unused-vars - const { children, role, ...restProps } = cellProps; + const { children, ...restProps } = cellProps as any; const columnClassname = cell?.column?.className; const content = children || ( <> @@ -179,7 +181,7 @@ const DatagridRow = (datagridState) => { return cell.render('Cell', { key: cell.column.id }); } const title = content?.props?.children[0]?.props?.value; - const associatedHeader = headers.filter( + const associatedHeader = headers?.filter( (h) => h.id === cell.column.id ); return ( @@ -207,7 +209,7 @@ const DatagridRow = (datagridState) => { ); })} - {renderExpandedRow()} + {renderExpandedRow?.() || undefined} ); }; diff --git a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridSelectAll.js b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridSelectAll.tsx similarity index 85% rename from packages/ibm-products/src/components/Datagrid/Datagrid/DatagridSelectAll.js rename to packages/ibm-products/src/components/Datagrid/Datagrid/DatagridSelectAll.tsx index 3c83f671dc..cd90b7e690 100644 --- a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridSelectAll.js +++ b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridSelectAll.tsx @@ -10,10 +10,11 @@ import { TableSelectAll } from '@carbon/react'; import cx from 'classnames'; import { pkg } from '../../../settings'; import { handleSelectAllRowData } from './addons/stateReducer'; +import { DataGridState, DataGridToggleAllRowsProps } from '../types'; const blockClass = `${pkg.prefix}--datagrid`; -const SelectAll = (datagridState) => { +const SelectAll = (datagridState: DataGridState) => { const [windowSize, setWindowSize] = useState( typeof window !== 'undefined' ? window.innerWidth : '' ); @@ -52,7 +53,7 @@ const SelectAll = (datagridState) => { className={cx(`${blockClass}__head-hidden-select-all`, { [`${blockClass}__select-all-sticky-left`]: /* istanbul ignore next */ - isFirstColumnStickyLeft && windowSize > 671, + isFirstColumnStickyLeft && Number(windowSize) > 671, })} /> ); @@ -60,7 +61,7 @@ const SelectAll = (datagridState) => { const getProps = DatagridPagination ? getToggleAllPageRowsSelectedProps : getToggleAllRowsSelectedProps; - const { onChange, ...selectProps } = getProps(); + const { onChange, ...selectProps } = getProps() as DataGridToggleAllRowsProps; const { indeterminate } = selectProps; const handleSelectAllChange = (event) => { @@ -70,19 +71,21 @@ const SelectAll = (datagridState) => { rows, getRowId, indeterminate: true, + isChecked: undefined, }); toggleAllRowsSelected(false); onAllRowSelect?.(rows, event); return onChange?.({ target: { checked: false }, - }); + } as any); } handleSelectAllRowData({ dispatch, rows, getRowId, isChecked: event.target.checked, + indeterminate, }); onAllRowSelect?.(rows, event); return onChange?.(event); @@ -96,7 +99,7 @@ const SelectAll = (datagridState) => { { [`${blockClass}__checkbox-cell-sticky-left`]: /* istanbul ignore next */ - isFirstColumnStickyLeft && windowSize > 671, + isFirstColumnStickyLeft && Number(windowSize) > 671, } )} > @@ -104,7 +107,7 @@ const SelectAll = (datagridState) => { {...selectProps} name={`${tableId}-select-all-checkbox-name`} onSelect={handleSelectAllChange} - disabled={isFetching || selectProps.disabled} + disabled={isFetching || selectProps?.disabled} id={`${tableId}-select-all-checkbox-id`} /> diff --git a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridSelectAllWithToggle.js b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridSelectAllWithToggle.tsx similarity index 84% rename from packages/ibm-products/src/components/Datagrid/Datagrid/DatagridSelectAllWithToggle.js rename to packages/ibm-products/src/components/Datagrid/Datagrid/DatagridSelectAllWithToggle.tsx index e7a454c671..e35cebc6f7 100644 --- a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridSelectAllWithToggle.js +++ b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridSelectAllWithToggle.tsx @@ -11,6 +11,7 @@ import cx from 'classnames'; import { Checkbox, OverflowMenu, OverflowMenuItem } from '@carbon/react'; import { CaretDown } from '@carbon/react/icons'; import { pkg } from '../../../settings'; +import { DataGridState, DataGridToggleAllRowsProps } from '../types'; const blockClass = `${pkg.prefix}--datagrid`; @@ -28,7 +29,7 @@ const SelectAllWithToggle = ({ allRowsLabel = 'Select all', columns, withStickyColumn, -}) => { +}: DataGridState) => { const { onSelectAllRows, labels } = selectAllToggle || {}; const [selectAllMode, setSelectAllMode] = useState(SELECT_ALL_PAGE_ROWS); useEffect(() => { @@ -47,17 +48,17 @@ const SelectAllWithToggle = ({ }, []); if (labels) { - allPageRowsLabel = labels.allPageRows || allPageRowsLabel; + allPageRowsLabel = labels?.allPageRows || allPageRowsLabel; allRowsLabel = labels.allRows || allRowsLabel; } const getProps = selectAllMode === SELECT_ALL_PAGE_ROWS ? getToggleAllPageRowsSelectedProps : getToggleAllRowsSelectedProps; - const { onChange, ...selectProps } = getProps(); + const { onChange, ...selectProps } = getProps() as DataGridToggleAllRowsProps; const disabled = isFetching || selectProps.disabled; const isFirstColumnStickyLeft = - columns[0]?.sticky === 'left' && withStickyColumn; + columns?.[0]?.sticky === 'left' && withStickyColumn; return (
: null} - {datagridState.headers - .filter(({ isVisible }) => isVisible) - .map((header, index) => { + {datagridState?.headers + ?.filter(({ isVisible }) => isVisible) + ?.map((header, index) => { if (header.id === selectionColumnId) { // render directly without the wrapper TableHeader return header.render('Header', { key: header.id }); @@ -187,25 +216,21 @@ const HeaderRow = (datagridState, headRef, headerGroup) => { const { columnResizing } = state; const { columnWidths } = columnResizing || {}; const originalCol = visibleColumns[index]; - const { - // eslint-disable-next-line no-unused-vars - role, - ...headerProps - } = header.getHeaderProps(); + const { ...headerProps } = header.getHeaderProps(); const resizerProps = header?.getResizerProps?.(); return ( { ); }; -const useHeaderRow = (hooks) => { - const useInstance = (instance) => { +const useHeaderRow = (hooks: DatagridTableHooks) => { + const useInstance = (instance: DataGridTableInstance) => { Object.assign(instance, { HeaderRow }); }; hooks.useInstance.push(useInstance); diff --git a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridRefBody.js b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridRefBody.tsx similarity index 82% rename from packages/ibm-products/src/components/Datagrid/Datagrid/DatagridRefBody.js rename to packages/ibm-products/src/components/Datagrid/Datagrid/DatagridRefBody.tsx index ff44e135de..f3e2d8b2da 100644 --- a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridRefBody.js +++ b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridRefBody.tsx @@ -8,6 +8,7 @@ import React from 'react'; import cx from 'classnames'; import { pkg } from '../../../settings'; +import { DataGridState } from '../types'; const blockClass = `${pkg.prefix}--datagrid`; @@ -15,7 +16,7 @@ const blockClass = `${pkg.prefix}--datagrid`; // hence no way to pass the ref to html element without changes in carbon side // define html directly here. // ref should be passed in thru getTableBodyProps -const DatagridRefBody = (datagridState) => { +const DatagridRefBody = (datagridState: DataGridState) => { const { getTableBodyProps, rows, prepareRow } = datagridState; return (
{ - onChange(e); + onClick={(e: any) => { + onChange?.(e); }} disabled={disabled} id={`${tableId}-select-all-checkbox-id`} - labelText={allRowsLabel} + labelText={allRowsLabel as string} hideLabel /> @@ -86,28 +87,28 @@ const SelectAllWithToggle = ({ menuOptionsClass={`${blockClass}__select-all-toggle-overflow`} > { setSelectAllMode(SELECT_ALL_PAGE_ROWS); // deselect all rows first - getToggleAllRowsSelectedProps().onChange({ + (getToggleAllRowsSelectedProps as any)?.()?.onChange({ target: { checked: false }, }); // select all row on current page - getToggleAllPageRowsSelectedProps().onChange({ + (getToggleAllPageRowsSelectedProps as any)().onChange({ target: { checked: true }, }); }} /> { setSelectAllMode(SELECT_ALL_ROWS); - getToggleAllRowsSelectedProps().onChange({ + (getToggleAllRowsSelectedProps as any)().onChange({ target: { checked: true }, }); }} diff --git a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridSimpleBody.js b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridSimpleBody.tsx similarity index 83% rename from packages/ibm-products/src/components/Datagrid/Datagrid/DatagridSimpleBody.js rename to packages/ibm-products/src/components/Datagrid/Datagrid/DatagridSimpleBody.tsx index c544ff47ba..d0f3ccd26b 100644 --- a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridSimpleBody.js +++ b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridSimpleBody.tsx @@ -9,10 +9,11 @@ import React from 'react'; import { TableBody } from '@carbon/react'; import cx from 'classnames'; import { pkg } from '../../../settings'; +import { DataGridState } from '../types'; const blockClass = `${pkg.prefix}--datagrid`; -const DatagridSimpleBody = (datagridState) => { +const DatagridSimpleBody = (datagridState: DataGridState) => { const { getTableBodyProps, rows, prepareRow } = datagridState; return ( { {rows.map((row) => { prepareRow(row); const { key } = row.getRowProps(); - return row.RowRenderer({ ...datagridState, row, key }); + return row?.RowRenderer?.({ ...datagridState, row, key }); })} ); diff --git a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridToolbar.js b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridToolbar.tsx similarity index 86% rename from packages/ibm-products/src/components/Datagrid/Datagrid/DatagridToolbar.js rename to packages/ibm-products/src/components/Datagrid/Datagrid/DatagridToolbar.tsx index b27d8d6095..8976f5f1ad 100644 --- a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridToolbar.js +++ b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridToolbar.tsx @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import React, { useEffect, useRef, useState } from 'react'; +import React, { useRef, MutableRefObject, useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import { TableToolbar, @@ -18,10 +18,19 @@ import { useResizeObserver } from '../../../global/js/hooks/useResizeObserver'; import { pkg, carbon } from '../../../settings'; import cx from 'classnames'; import { handleSelectAllRowData } from './addons/stateReducer'; +import { DataGridState } from '../types'; const blockClass = `${pkg.prefix}--datagrid__table-toolbar`; -const DatagridBatchActionsToolbar = (datagridState, width, ref) => { +interface DatagridToolbarProps { + ariaToolbarLabel?: string; +} + +const DatagridBatchActionsToolbar = ( + datagridState: DataGridState, + width: number, + ref: MutableRefObject +) => { const [displayAllInMenu, setDisplayAllInMenu] = useState(false); const [initialListWidth, setInitialListWidth] = useState(null); const [receivedInitialWidth, setReceivedInitialWidth] = useState(false); @@ -46,7 +55,7 @@ const DatagridBatchActionsToolbar = (datagridState, width, ref) => { // the ButtonMenu useEffect(() => { if (totalSelected === 1 && !receivedInitialWidth) { - const batchActionListWidth = ref.current.querySelector( + const batchActionListWidth = ref?.current?.querySelector( `.${carbon.prefix}--action-list` ).offsetWidth; setInitialListWidth(batchActionListWidth); @@ -55,7 +64,7 @@ const DatagridBatchActionsToolbar = (datagridState, width, ref) => { }, [totalSelected, receivedInitialWidth, ref]); useEffect(() => { - const summaryWidth = ref.current.querySelector( + const summaryWidth = ref?.current.querySelector( `.${carbon.prefix}--batch-summary` ).offsetWidth; if (width < summaryWidth + initialListWidth + 32) { @@ -83,7 +92,11 @@ const DatagridBatchActionsToolbar = (datagridState, width, ref) => { const minWidthBeforeOverflowIcon = 380; // Do not render ButtonMenu when there are 3 or less items // and if there is enough available space to render all the items - if (toolbarBatchActions?.length <= 3 && !displayAllInMenu) { + if ( + toolbarBatchActions && + toolbarBatchActions?.length <= 3 && + !displayAllInMenu + ) { return; } @@ -105,6 +118,7 @@ const DatagridBatchActionsToolbar = (datagridState, width, ref) => { }, ])} tabIndex={totalSelected > 0 ? 0 : -1} + menuAlignment="bottom" > {toolbarBatchActions?.map((batchAction, index) => { const hidden = index < 2 && !displayAllInMenu; @@ -129,9 +143,10 @@ const DatagridBatchActionsToolbar = (datagridState, width, ref) => { rows: [], getRowId, isChecked: false, + indeterminate: undefined, }); toggleAllRowsSelected(false); - setGlobalFilter(null); + setGlobalFilter?.(null); }; const onSelectAllHandler = () => { @@ -141,6 +156,8 @@ const DatagridBatchActionsToolbar = (datagridState, width, ref) => { dispatch, rows, getRowId, + indeterminate: undefined, + isChecked: undefined, }); }; @@ -181,14 +198,15 @@ const DatagridBatchActionsToolbar = (datagridState, width, ref) => { ); }; -const DatagridToolbar = ({ ariaToolbarLabel, ...datagridState }) => { +const DatagridToolbar = ({ + ariaToolbarLabel, + ...datagridState +}: DatagridToolbarProps & DataGridState) => { const ref = useRef(null); const { width } = useResizeObserver(ref); const { DatagridActions, DatagridBatchActions, batchActions, rowSize } = datagridState; - const getRowHeight = rowSize || 'lg'; - return batchActions && DatagridActions ? (
{ > {DatagridActions && } - {DatagridBatchActionsToolbar && - DatagridBatchActionsToolbar(datagridState, width, ref)} + {DatagridBatchActionsToolbar?.(datagridState, width, ref)}
) : DatagridActions ? (
{DatagridActions && } - {DatagridBatchActions && DatagridBatchActions(datagridState)} + {DatagridBatchActions?.(datagridState)}
) : null; diff --git a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridVirtualBody.js b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridVirtualBody.tsx similarity index 65% rename from packages/ibm-products/src/components/Datagrid/Datagrid/DatagridVirtualBody.js rename to packages/ibm-products/src/components/Datagrid/Datagrid/DatagridVirtualBody.tsx index 1b3bb2e4df..0fb374dcbf 100644 --- a/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridVirtualBody.js +++ b/packages/ibm-products/src/components/Datagrid/Datagrid/DatagridVirtualBody.tsx @@ -5,13 +5,14 @@ * LICENSE file in the root directory of this source tree. */ -import React, { useEffect, useRef } from 'react'; +import React, { MutableRefObject, useEffect, useRef } from 'react'; import { VariableSizeList } from 'react-window'; import { TableBody } from '@carbon/react'; import { pkg } from '../../../settings'; import DatagridHead from './DatagridHead'; import { px } from '@carbon/layout'; import { useResizeObserver } from '../../../global/js/hooks/useResizeObserver'; +import { DataGridState, DatagridRow } from '../types'; const blockClass = `${pkg.prefix}--datagrid`; @@ -25,7 +26,7 @@ const rowSizeMap = { const defaultRowHeight = rowSizeMap.lg; -const DatagridVirtualBody = (datagridState) => { +const DatagridVirtualBody = (datagridState: DataGridState) => { const { getTableBodyProps, rows, @@ -47,43 +48,54 @@ const DatagridVirtualBody = (datagridState) => { /* istanbul ignore next */ const handleVirtualGridResize = () => { const gridRefElement = gridRef?.current; - gridRefElement.style.width = gridRefElement?.clientWidth; + if (gridRefElement) { + gridRefElement.style.width = gridRefElement?.clientWidth?.toString(); + } }; useResizeObserver(gridRef, handleVirtualGridResize); useEffect(() => { - handleResize(); + handleResize?.(); }, [handleResize]); const rowHeight = (rowSize && rowSizeMap[rowSize]) || defaultRowHeight; - if (listRef && listRef.current) { - listRef.current.resetAfterIndex(0); - } - const visibleRows = (DatagridPagination && page) || rows; - const testRef = useRef(); + useEffect(() => { + if (listRef && listRef.current) { + listRef.current.resetAfterIndex(0); + } + }, [listRef]); + + const visibleRows = ((DatagridPagination && page) || rows) as DatagridRow[]; + const testRef: MutableRefObject = useRef(null); // Sync the scrollLeft position of the virtual body to the table header useEffect(() => { function handleScroll(event) { const virtualBody = event.target; - document.querySelector( + const headWrapEl = document?.querySelector( `#${tableId} .${blockClass}__head-wrap` - ).scrollLeft = virtualBody.scrollLeft; - const spacerColumn = document.querySelector( + ); + if (headWrapEl) { + headWrapEl.scrollLeft = virtualBody?.scrollLeft; + } + const spacerColumn: HTMLDivElement | null = document.querySelector( `#${tableId} .${blockClass}__head-wrap thead th:last-child` ); - spacerColumn.style.width = px( - 32 + (virtualBody.offsetWidth - virtualBody.clientWidth) - ); // scrollbar width to header column to fix header alignment + + if (spacerColumn) { + spacerColumn.style.width = px( + 32 + (virtualBody.offsetWidth - virtualBody.clientWidth) + ); // scrollbar width to header column to fix header alignment + } } - const testRefValue = testRef.current; - testRefValue.addEventListener('scroll', handleScroll); + const testRefValue = testRef?.current; + testRefValue?.addEventListener('scroll', handleScroll); return () => { - testRefValue.removeEventListener('scroll', handleScroll); + testRefValue?.removeEventListener('scroll', handleScroll); }; }); @@ -91,7 +103,7 @@ const DatagridVirtualBody = (datagridState) => { <>
@@ -100,7 +112,7 @@ const DatagridVirtualBody = (datagridState) => { height={virtualHeight || tableHeight} itemCount={visibleRows.length} itemSize={(index) => - visibleRows[index].isExpanded + visibleRows[index]?.isExpanded ? (visibleRows[index].expandedContentHeight || 0) + rowHeight : rowHeight } @@ -111,7 +123,7 @@ const DatagridVirtualBody = (datagridState) => { outerRef={testRef} ref={listRef} className={`${blockClass}__virtual-scrollbar`} - style={{ width: gridRef.current?.clientWidth }} + style={{ width: gridRef?.current?.clientWidth }} > {({ index, style }) => { const row = visibleRows[index]; @@ -123,7 +135,7 @@ const DatagridVirtualBody = (datagridState) => { ...style, }} > - {row.RowRenderer({ ...datagridState, row, key })} + {row?.RowRenderer?.({ ...datagridState, row, key })} ); }} diff --git a/packages/ibm-products/src/components/Datagrid/Datagrid/DraggableElement.js b/packages/ibm-products/src/components/Datagrid/Datagrid/DraggableElement.tsx similarity index 85% rename from packages/ibm-products/src/components/Datagrid/Datagrid/DraggableElement.js rename to packages/ibm-products/src/components/Datagrid/Datagrid/DraggableElement.tsx index 1286b98b70..bf557091c5 100644 --- a/packages/ibm-products/src/components/Datagrid/Datagrid/DraggableElement.js +++ b/packages/ibm-products/src/components/Datagrid/Datagrid/DraggableElement.tsx @@ -6,7 +6,7 @@ * US Government Users Restricted Rights - Use, duplication or disclosure * restricted by GSA ADP Schedule Contract with IBM Corp. */ -import React from 'react'; +import React, { PropsWithChildren, ReactNode } from 'react'; import PropTypes from 'prop-types'; import { Draggable as DraggableIcon, Locked } from '@carbon/react/icons'; import cx from 'classnames'; @@ -16,6 +16,16 @@ import { useSortable } from '@dnd-kit/sortable'; const blockClass = `${pkg.prefix}--datagrid`; +interface DraggableElementProps extends PropsWithChildren { + ariaLabel: string; + children: ReactNode; + classList?: string; + disabled?: boolean; + id: string; + isSticky?: boolean; + selected?: boolean; +} + const DraggableElement = ({ id, children, @@ -24,7 +34,7 @@ const DraggableElement = ({ ariaLabel, isSticky, selected, -}) => { +}: DraggableElementProps) => { const { attributes, isDragging, @@ -54,7 +64,7 @@ const DraggableElement = ({ ); const style = { - transform: !disabled ? CSS.Transform.toString(transform) : {}, + transform: !disabled ? CSS.Transform.toString(transform) : undefined, transition, }; @@ -70,7 +80,6 @@ const DraggableElement = ({ style={style} {...attributes} {...listeners} - disabled={disabled} aria-selected={selected} role="option" > diff --git a/packages/ibm-products/src/components/Datagrid/Datagrid/addons/Filtering/FilterPanel.js b/packages/ibm-products/src/components/Datagrid/Datagrid/addons/Filtering/FilterPanel.js index 6f34486045..692b2625dd 100644 --- a/packages/ibm-products/src/components/Datagrid/Datagrid/addons/Filtering/FilterPanel.js +++ b/packages/ibm-products/src/components/Datagrid/Datagrid/addons/Filtering/FilterPanel.js @@ -320,7 +320,7 @@ FilterPanel.propTypes = { searchLabelText: PropTypes.string, searchPlaceholder: PropTypes.string, secondaryActionLabel: PropTypes.string, - setAllFilters: PropTypes.func.isRequired, + setAllFilters: PropTypes.func, showFilterSearch: PropTypes.bool, title: PropTypes.string, updateMethod: PropTypes.oneOf([BATCH, INSTANT]), diff --git a/packages/ibm-products/src/components/Datagrid/Datagrid/addons/Slug/DatagridSlug.js b/packages/ibm-products/src/components/Datagrid/Datagrid/addons/Slug/DatagridSlug.js deleted file mode 100644 index 423a0e2f04..0000000000 --- a/packages/ibm-products/src/components/Datagrid/Datagrid/addons/Slug/DatagridSlug.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright IBM Corp. 2024, 2024 - * - * This source code is licensed under the Apache-2.0 license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React, { forwardRef, isValidElement } from 'react'; -import PropTypes from 'prop-types'; - -export const DatagridSlug = forwardRef(({ slug }, ref) => { - if (slug && isValidElement(slug)) { - const normalizedSlug = React.cloneElement(slug, { - size: 'mini', - ref, - }); - return normalizedSlug; - } - return null; -}); - -DatagridSlug.propTypes = { - /** - * Specify the AI slug to be displayed - */ - slug: PropTypes.node, -}; diff --git a/packages/ibm-products/src/components/Datagrid/Datagrid/addons/Slug/DatagridSlug.tsx b/packages/ibm-products/src/components/Datagrid/Datagrid/addons/Slug/DatagridSlug.tsx new file mode 100644 index 0000000000..614294fdb5 --- /dev/null +++ b/packages/ibm-products/src/components/Datagrid/Datagrid/addons/Slug/DatagridSlug.tsx @@ -0,0 +1,43 @@ +/** + * Copyright IBM Corp. 2024, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, { + ForwardedRef, + ReactNode, + forwardRef, + isValidElement, +} from 'react'; +import PropTypes from 'prop-types'; + +interface DatagridSlugProps { + slug?: ReactNode; +} + +interface NormalizedSlugProps { + size?: string; + ref?: ForwardedRef; +} + +export const DatagridSlug = forwardRef( + ({ slug }: DatagridSlugProps, ref: ForwardedRef) => { + if (slug && isValidElement(slug)) { + const normalizedSlug = React.cloneElement(slug, { + size: 'mini', + ref, + } as NormalizedSlugProps); + return normalizedSlug; + } + return null; + } +); + +DatagridSlug.propTypes = { + /** + * Specify the AI slug to be displayed + */ + slug: PropTypes.node, +}; diff --git a/packages/ibm-products/src/components/Datagrid/Datagrid/index.js b/packages/ibm-products/src/components/Datagrid/Datagrid/index.ts similarity index 100% rename from packages/ibm-products/src/components/Datagrid/Datagrid/index.js rename to packages/ibm-products/src/components/Datagrid/Datagrid/index.ts diff --git a/packages/ibm-products/src/components/Datagrid/types/index.ts b/packages/ibm-products/src/components/Datagrid/types/index.ts new file mode 100644 index 0000000000..3e66adc68d --- /dev/null +++ b/packages/ibm-products/src/components/Datagrid/types/index.ts @@ -0,0 +1,281 @@ +import { MultiSelectProps } from '@carbon/react/lib/components/MultiSelect/MultiSelect'; +import { FormGroupProps } from '@carbon/react/lib/components/FormGroup/FormGroup'; +import { RadioButtonProps } from '@carbon/react/lib/components/RadioButton/RadioButton'; +import { RadioButtonGroupProps } from '@carbon/react/lib/components/RadioButtonGroup/RadioButtonGroup'; +import { CheckboxProps } from '@carbon/react/lib/components/Checkbox'; +import { NumberInputProps } from '@carbon/react/lib/components/NumberInput/NumberInput'; + +import { + CSSProperties, + JSXElementConstructor, + MutableRefObject, + ReactNode, + TouchEventHandler, +} from 'react'; +import { + Cell, + ColumnInstance, + FilterValue, + Filters, + HeaderGroup, + Row, + TableCommonProps, + TableDispatch, + TableInstance, + TableToggleAllRowsSelectedProps, + UseExpandedRowProps, + UseFiltersInstanceProps, + UsePaginationInstanceProps, + UseResizeColumnsColumnProps, + UseResizeColumnsState, + UseRowSelectInstanceProps, + UseRowSelectRowProps, + UseRowSelectState, + UseSortByColumnProps, + UseTableHooks, +} from 'react-table'; +import { CarbonIconType } from '@carbon/react/icons'; +import { type ButtonProps } from '@carbon/react'; +import { TableBatchActionsProps } from '@carbon/react/lib/components/DataTable/TableBatchActions'; + +export type Size = 'xs' | 'sm' | 'md' | 'lg'; + +export interface ResizerProps { + draggable?: boolean; + onMouseDown?: (evt: any) => void; + onTouchStart?: TouchEventHandler; + role?: string; + style?: CSSProperties; +} + +export type DataGridFilter = + | ({ + column?: string; + } & { + type: 'date'; + props: { + // DatePickerProps + DatePicker?: any; + // DatePickerInputProps + DatePickerInput?: any; + }; + }) + | { + type: 'number'; + props: { + NumberInput?: NumberInputProps; + }; + } + | { + type: 'checkbox'; + props: { + FormGroup?: FormGroupProps; + Checkbox?: CheckboxProps[]; + }; + } + | { + type: 'radio'; + props: { + FormGroup?: FormGroupProps; + RadioButton?: RadioButtonProps[]; + RadioButtonGroup?: RadioButtonGroupProps; + }; + } + | { + type: 'multiSelect'; + props: { + MultiSelect?: MultiSelectProps; + }; + }; + +export interface ReactTableFiltersState { + id: string; + type: string; + value: string; +} + +interface Labels { + allPageRows?: object; + allRows?: object; +} + +interface Section { + categoryTitle?: string; + filters?: DataGridFilter[]; +} + +export interface FilterFlyoutProps { + data?: any; + filters?: DataGridFilter[]; + flyoutIconDescription?: string; + onFlyoutClose?: () => void; + onFlyoutOpen?: () => void; + panelIconDescription?: string; + primaryActionLabel?: string; + reactTableFiltersState?: ReactTableFiltersState[]; + renderLabel?: () => void; + secondaryActionLabel?: string; + updateMethod?: string; + variation?: string; + panelTitle?: string; + sections?: Section[]; + autoHideFilters: boolean; +} + +export interface DataGridToggleAllRowsProps + extends TableToggleAllRowsSelectedProps { + disabled?: boolean; +} + +export interface DatagridTableHooks + extends UseTableHooks {} + +export interface DatagridColumn + extends ColumnInstance { + sticky?: 'left' | 'right'; + className?: string; +} + +export interface DataGridCell + extends Omit, 'column'> { + column: DatagridColumn; +} + +export interface DatagridRow + extends Omit, 'cells'>, + UseExpandedRowProps, + UseRowSelectRowProps { + expandedContentHeight?: number; + RowRenderer?: (state?: DataGridState) => ReactNode; + RowExpansionRenderer?: (state?: DataGridState) => void; + cells: Array; + isSkeleton?: boolean; +} + +export interface DataGridHeader + extends ColumnInstance, + UseResizeColumnsColumnProps, + UseSortByColumnProps { + className(className: any, arg1: { [x: string]: any }): unknown; + isAction?: boolean; + slug?: any; +} + +export interface DataGridHeaderGroup + extends HeaderGroup, + UseResizeColumnsColumnProps {} + +export interface TableProps { + className?: string; + role?: string; + style?: CSSStyleDeclaration; +} + +interface DataGridTableState + extends UseResizeColumnsState, + UseRowSelectState { + filters: Filters; +} + +export interface DataGridTableInstance + extends TableInstance {} + +export interface DataGridState + extends TableCommonProps, + UsePaginationInstanceProps, + Omit, 'state' | 'headers' | 'rows' | 'columns'>, + Omit, 'rows'>, + UseRowSelectInstanceProps, + Pick, 'toggleAllRowsSelected'> { + withVirtualScroll?: boolean; + DatagridPagination?: JSXElementConstructor; + isFetching?: boolean; + tableId?: string; + filterProps?: FilterFlyoutProps; + state: DataGridTableState; + getFilterFlyoutProps?: () => FilterFlyoutProps; + DatagridActions?: JSXElementConstructor; + CustomizeColumnsTearsheet?: JSXElementConstructor; + fullHeightDatagrid?: boolean; + variableRowHeight?: boolean; + useDenseHeader?: boolean; + withInlineEdit?: boolean; + verticalAlign?: string; + gridTitle?: ReactNode; + gridDescription?: ReactNode; + gridRef?: MutableRefObject; + DatagridBatchActions?: (args) => ReactNode; + batchActions?: boolean; + row: DatagridRow; + rows: Array>; + columns: Array; + key?: any; + rowSize?: Size; + headers?: Array>; + headRef?: MutableRefObject; + HeaderRow?: ( + state?: object, + ref?: MutableRefObject, + group?: HeaderGroup + ) => ReactNode; + withStickyColumn?: boolean; + emptyStateTitle?: string | ReactNode; + emptyStateDescription?: string; + emptyStateSize?: 'lg' | 'sm'; + emptyStateType?: string; + illustrationTheme?: 'light' | 'dark'; + emptyStateAction: { + kind?: 'primary' | 'secondary' | 'tertiary'; + renderIcon?: CarbonIconType; + onClick?: ButtonProps['onClick']; + text?: string; + }; + emptyStateLink?: { + text?: string | ReactNode; + href?: string; + }; + isTableSortable?: boolean; + resizerAriaLabel?: string; + onColResizeEnd?: () => void; + withNestedRows?: boolean; + withExpandedRows?: boolean; + withMouseHover?: boolean; + setMouseOverRowIndex?: (arg: any) => void; + hideSelectAll?: boolean; + radio?: boolean; + onAllRowSelect: (rows: DatagridRow[], evt: any) => void; + selectAllToggle?: { + onSelectAllRows?: (args) => void; + labels?: Labels; + }; + allPageRowsLabel?: string | object; + allRowsLabel: string | object; + onSelectAllRows?: (val?: boolean) => void; + toolbarBatchActions?: ButtonProps[]; + setGlobalFilter?: (filterValue: FilterValue) => void; + batchActionMenuButtonLabel?: string; + translateWithIdBatchActions?: TableBatchActionsProps['translateWithId']; + onScroll?: (evt?: any) => void; + innerListRef?: MutableRefObject; + tableHeight?: number; + virtualHeight?: number; + listRef?: MutableRefObject; + handleResize?: () => void; + onVirtualScroll?: (evt?: boolean) => void; +} + +// DatagridHeaderRow related types +export interface ResizeHeaderProps { + resizerProps?: ResizerProps; + header: DataGridHeader; + originalCol?: DatagridColumn; + handleOnMouseDownResize?: (evt?: any, props?: ResizerProps) => void; + columnWidths?: any[]; + datagridState: DataGridState; + incrementAmount: number; + minWidth?: number; + dispatch?: TableDispatch; + onColResizeEnd?: () => void; + resizerAriaLabel?: string; + isFetching?: boolean; +} diff --git a/packages/ibm-products/src/components/Datagrid/useSelectRows.js b/packages/ibm-products/src/components/Datagrid/useSelectRows.js index cbc54c6c99..9ef8684677 100644 --- a/packages/ibm-products/src/components/Datagrid/useSelectRows.js +++ b/packages/ibm-products/src/components/Datagrid/useSelectRows.js @@ -124,9 +124,12 @@ const SelectRow = (datagridState) => { const isFirstColumnStickyLeft = columns[0]?.sticky === 'left' && withStickyColumn; const rowId = `${tableId}-${row.id}-${row.index}`; + const { key, _cellProps } = cellProps; + return ( void; + clearFiltersText?: string; + filters: Filter[]; + overflowType?: 'default' | 'tag'; + renderLabel?: (key, value) => void; +} + +type PrevState = { + multiline?: boolean; +}; + +const FilterSummary = React.forwardRef( ( { className = '', clearFiltersText = 'Clear filters', clearFilters, filters, - renderLabel = null, + renderLabel, overflowType = 'default', clearButtonInline = true, ...rest - }, - ref + }: FilterSummaryProps, + ref: ForwardedRef ) => { const filterSummaryId = `${blockClass}__${uuidv4()}`; const tagFilters = filters.map(({ key, value, ...rest }) => { @@ -44,13 +62,19 @@ let FilterSummary = React.forwardRef( }; }); - const filterSummaryClearButton = useRef(); - const viewAllButtonRef = useRef(); - const filterSummaryRef = useRef(); + const filterSummaryClearButton: MutableRefObject = + useRef(null); + const viewAllButtonRef: MutableRefObject = + useRef(null); + const filterSummaryRef: MutableRefObject = + useRef(null); const localRef = filterSummaryRef || ref; const [overflowCount, setOverflowCount] = useState(0); const [multiline, setMultiline] = useState(false); - const previousState = usePreviousValue({ multiline }); + const previousState: PrevState = + usePreviousValue({ + multiline, + }) || {}; const handleViewAll = () => { if (overflowCount === 0) { @@ -67,7 +91,7 @@ let FilterSummary = React.forwardRef( ? 48 : 0; const measurementOffset = - filterSummaryClearButton?.current?.offsetWidth + viewAllWidth; + (filterSummaryClearButton?.current?.offsetWidth || 0) + viewAllWidth; const renderTagSet = (type) => ( - setOverflowCount(overflowTags.length) + onOverflowTagChange={(overflowTags: any) => + setOverflowCount(overflowTags?.length) } multiline={multiline} /> @@ -111,7 +135,11 @@ let FilterSummary = React.forwardRef( useWindowResize(() => { const handleFilterSummaryResize = () => { - if (multiline && localRef?.current?.offsetHeight <= 50) { + if ( + multiline && + localRef?.current?.offsetHeight && + localRef?.current?.offsetHeight <= 50 + ) { setMultiline(false); } }; @@ -129,7 +157,7 @@ let FilterSummary = React.forwardRef( [`${blockClass}__expanded`]: multiline, })} > - + {!multiline && renderTagSet('single')} {multiline && renderTagSet('multiline')} @@ -174,6 +202,7 @@ FilterSummary.propTypes = { clearButtonInline: PropTypes.bool, clearFilters: PropTypes.func.isRequired, clearFiltersText: PropTypes.string, + /**@ts-ignore */ filters: PropTypes.arrayOf(PropTypes.object).isRequired, overflowType: PropTypes.oneOf(['default', 'tag']), renderLabel: PropTypes.func, diff --git a/packages/ibm-products/src/custom-typings/index.d.ts b/packages/ibm-products/src/custom-typings/index.d.ts index d6ce4780f5..3ffd6baa03 100644 --- a/packages/ibm-products/src/custom-typings/index.d.ts +++ b/packages/ibm-products/src/custom-typings/index.d.ts @@ -147,6 +147,8 @@ declare module '@carbon/react' { TabPanels, Table, Table, + TableBatchAction, + TableBatchActions, TableBody, TableBody, TableCell, @@ -164,6 +166,7 @@ declare module '@carbon/react' { TableSelectAll, TableSelectAllProps, TableSelectRow, + TableToolbar, TableToolbarSearch, Tabs, Tabs, diff --git a/yarn.lock b/yarn.lock index 9e859a8490..694f7a5d9d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1846,6 +1846,7 @@ __metadata: "@rollup/plugin-commonjs": "npm:^25.0.0" "@rollup/plugin-node-resolve": "npm:^15.0.0" "@rollup/plugin-typescript": "npm:^11.0.0" + "@types/react-table": "npm:^7.7.20" babel-plugin-dev-expression: "npm:^0.2.3" babel-preset-ibm-cloud-cognitive: "npm:^0.14.40" chalk: "npm:^4.1.2" @@ -6830,6 +6831,15 @@ __metadata: languageName: node linkType: hard +"@types/react-table@npm:^7.7.20": + version: 7.7.20 + resolution: "@types/react-table@npm:7.7.20" + dependencies: + "@types/react": "npm:*" + checksum: adf86958dd5b2e044d23fc7896f758b5ec59987891b41e9b02d935d666e999a518b0bdd8ba5bd60d644f20147de0ec3cf5f6a12b75516f1fad43fb3b4fd8361f + languageName: node + linkType: hard + "@types/react@npm:*, @types/react@npm:^16.8.0 || ^17.0.0 || ^18.0.0": version: 18.3.1 resolution: "@types/react@npm:18.3.1"