From c891a298f1f4092bc25974e78b90146901d78374 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Wed, 4 Jun 2025 17:07:45 -0400 Subject: [PATCH 1/4] feat(React19): Add support for React19 --- packages/module/package.json | 4 +- .../content/examples/Actions.tsx | 4 +- .../content/examples/Basic.tsx | 4 +- .../examples/FilterableWithWindowScroller.tsx | 40 +++++++++---------- .../content/examples/Selectable.tsx | 9 +++-- .../content/examples/Sortable.tsx | 9 +++-- .../content/examples/WindowScroller.tsx | 6 +-- .../extensions/virtual-scroll-table/react.js | 16 ++++---- .../virtual-scroll-window-scroller/react.js | 8 ++-- .../module/patternfly-docs/generated/react.js | 10 ++--- .../module/patternfly-docs/pages/index.js | 1 - .../src/components/Virtualized/VirtualGrid.ts | 16 ++++---- .../Virtualized/VirtualTableBody.tsx | 8 ++-- .../Virtualized/VirtualizedTable.test.tsx | 1 - .../components/Virtualized/testDataSets.tsx | 8 ++-- .../src/components/Virtualized/types.ts | 10 ++--- packages/module/tsconfig.json | 2 +- 17 files changed, 79 insertions(+), 77 deletions(-) diff --git a/packages/module/package.json b/packages/module/package.json index e57a7b9..b621c20 100644 --- a/packages/module/package.json +++ b/packages/module/package.json @@ -47,8 +47,8 @@ "tslib": "^2.5.2" }, "peerDependencies": { - "react": "^17 || ^18", - "react-dom": "^17 || ^18" + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" }, "devDependencies": { "@patternfly/documentation-framework": "^6.0.0-alpha.109", diff --git a/packages/module/patternfly-docs/content/examples/Actions.tsx b/packages/module/patternfly-docs/content/examples/Actions.tsx index fde443d..a4c7f93 100644 --- a/packages/module/patternfly-docs/content/examples/Actions.tsx +++ b/packages/module/patternfly-docs/content/examples/Actions.tsx @@ -1,5 +1,5 @@ /* eslint-disable no-console */ -import React from 'react'; +import { FunctionComponent } from 'react'; import { ActionsColumn, Caption, @@ -14,7 +14,7 @@ import { import { CellMeasurerCache, CellMeasurer } from 'react-virtualized'; import { AutoSizer, VirtualTableBody } from '@patternfly/react-virtualized-extension'; -export const ActionsExample: React.FunctionComponent = () => { +export const ActionsExample: FunctionComponent = () => { interface RowType { disableActions: boolean; id: string; diff --git a/packages/module/patternfly-docs/content/examples/Basic.tsx b/packages/module/patternfly-docs/content/examples/Basic.tsx index 5042504..758c622 100644 --- a/packages/module/patternfly-docs/content/examples/Basic.tsx +++ b/packages/module/patternfly-docs/content/examples/Basic.tsx @@ -1,9 +1,9 @@ -import React from 'react'; +import { FunctionComponent } from 'react'; import { Caption, Table, TableGridBreakpoint, Td, Th, Thead, Tr } from '@patternfly/react-table'; import { CellMeasurerCache, CellMeasurer } from 'react-virtualized'; import { AutoSizer, VirtualTableBody } from '@patternfly/react-virtualized-extension'; -export const VirtualizedExample: React.FunctionComponent = () => { +export const VirtualizedExample: FunctionComponent = () => { // this StringArray type is just needed because something in our documentation framework crashes when it encounters // a string[][] type type StringArray = string[]; diff --git a/packages/module/patternfly-docs/content/examples/FilterableWithWindowScroller.tsx b/packages/module/patternfly-docs/content/examples/FilterableWithWindowScroller.tsx index 9ae4680..a9ff4fd 100644 --- a/packages/module/patternfly-docs/content/examples/FilterableWithWindowScroller.tsx +++ b/packages/module/patternfly-docs/content/examples/FilterableWithWindowScroller.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { CellMeasurerCache, CellMeasurer } from 'react-virtualized'; import { AutoSizer, VirtualTableBody, WindowScroller } from '@patternfly/react-virtualized-extension'; import { Table, Thead, Tr, Th, Td, TableGridBreakpoint, ActionsColumn, Tbody } from '@patternfly/react-table'; @@ -25,10 +24,11 @@ import { Bullseye } from '@patternfly/react-core'; import { FilterIcon, SearchIcon } from '@patternfly/react-icons'; +import { Fragment, useEffect, useState, CSSProperties, Ref, MouseEvent as ReactMouseEvent, SyntheticEvent, KeyboardEvent as ReactKeyboardEvent } from 'react'; export const ComposableTableWindowScroller = () => { - const [scrollableElement, setScrollableElement] = React.useState(); - React.useEffect(() => { + const [scrollableElement, setScrollableElement] = useState(); + useEffect(() => { const scrollableElement = document.getElementById('content-scrollable-2') as HTMLElement; setScrollableElement(scrollableElement); }, []); @@ -86,11 +86,11 @@ export const ComposableTableWindowScroller = () => { const columns = ['Servers', 'Threads', 'Applications', 'Status', 'Location']; const scrollToIndex = -1; // can be used to programmatically set current index - const [isCategoryDropdownOpen, setIsCategoryDropdownOpen] = React.useState(false); - const [isFilterDropdownOpen, setIsFilterDropdownOpen] = React.useState(false); - const [currentCategory, setCurrentCategory] = React.useState('Name'); - const [filters, setFilters] = React.useState>({ location: [], name: [], status: [] }); - const [inputValue, setInputValue] = React.useState(''); + const [isCategoryDropdownOpen, setIsCategoryDropdownOpen] = useState(false); + const [isFilterDropdownOpen, setIsFilterDropdownOpen] = useState(false); + const [currentCategory, setCurrentCategory] = useState('Name'); + const [filters, setFilters] = useState>({ location: [], name: [], status: [] }); + const [inputValue, setInputValue] = useState(''); const onDelete = (type: string | ToolbarLabelGroup, id: string) => { if (type === 'Location') { @@ -130,7 +130,7 @@ export const ComposableTableWindowScroller = () => { setInputValue(newValue); }; - const onStatusSelect = (event: React.MouseEvent | undefined, selection: string | number | undefined) => { + const onStatusSelect = (event: ReactMouseEvent | undefined, selection: string | number | undefined) => { const checked = (event?.target as HTMLInputElement).checked; setFilters({ ...filters, @@ -139,9 +139,9 @@ export const ComposableTableWindowScroller = () => { setIsFilterDropdownOpen(false); }; - const onNameInput = (event: React.SyntheticEvent | React.KeyboardEvent) => { + const onNameInput = (event: SyntheticEvent | ReactKeyboardEvent) => { setIsCategoryDropdownOpen(false); - const pressedKey = (event as React.KeyboardEvent).key; + const pressedKey = (event as ReactKeyboardEvent).key; if (pressedKey && pressedKey !== 'Enter') { return; } @@ -155,7 +155,7 @@ export const ComposableTableWindowScroller = () => { setIsCategoryDropdownOpen(false); }; - const onLocationSelect = (_event: React.MouseEvent | undefined, selection: string | number | undefined) => { + const onLocationSelect = (_event: ReactMouseEvent | undefined, selection: string | number | undefined) => { setFilters({ ...filters, location: [`${selection}`] }); setIsFilterDropdownOpen(false); @@ -180,7 +180,7 @@ export const ComposableTableWindowScroller = () => { - + ); }; diff --git a/packages/module/patternfly-docs/content/examples/Selectable.tsx b/packages/module/patternfly-docs/content/examples/Selectable.tsx index 638be6f..7e5469e 100644 --- a/packages/module/patternfly-docs/content/examples/Selectable.tsx +++ b/packages/module/patternfly-docs/content/examples/Selectable.tsx @@ -1,10 +1,11 @@ -import React from 'react'; +import { FunctionComponent } from 'react'; +import { useState } from 'react'; import { CellMeasurerCache, CellMeasurer } from 'react-virtualized'; import { AutoSizer, VirtualTableBody } from '@patternfly/react-virtualized-extension'; import { Table, Thead, Tr, Th, Td, Caption, TableGridBreakpoint } from '@patternfly/react-table'; -export const SelectableTableVirtualized: React.FunctionComponent = () => { +export const SelectableTableVirtualized: FunctionComponent = () => { // this StringArray type is just needed because something in our documentation framework crashes when it encounters // a string[][] type type StringArray = string[]; @@ -16,7 +17,7 @@ export const SelectableTableVirtualized: React.FunctionComponent = () => { const selectableRepos = rows; - const [selectedRepoNames, setSelectedRepoNames] = React.useState([]); + const [selectedRepoNames, setSelectedRepoNames] = useState([]); const setRepoSelected = (repo: string, isSelecting = true) => setSelectedRepoNames((prevSelected) => { @@ -31,7 +32,7 @@ export const SelectableTableVirtualized: React.FunctionComponent = () => { const areAllReposSelected = selectedRepoNames.length === selectableRepos.length; const isRepoSelected = (repo: string) => selectedRepoNames.includes(repo); - const [recentSelectedRowIndex, setRecentSelectedRowIndex] = React.useState(null); + const [recentSelectedRowIndex, setRecentSelectedRowIndex] = useState(null); const onSelectRepo = (repo: string, rowIndex: number, isSelecting: boolean) => { if (recentSelectedRowIndex !== null) { diff --git a/packages/module/patternfly-docs/content/examples/Sortable.tsx b/packages/module/patternfly-docs/content/examples/Sortable.tsx index 450b895..b0b05de 100644 --- a/packages/module/patternfly-docs/content/examples/Sortable.tsx +++ b/packages/module/patternfly-docs/content/examples/Sortable.tsx @@ -1,9 +1,10 @@ -import React from 'react'; +import type { FunctionComponent } from 'react'; +import { useState } from 'react'; import { Caption, Table, Td, Th, Thead, ThProps, Tr } from '@patternfly/react-table'; import { CellMeasurerCache, CellMeasurer } from 'react-virtualized'; import { AutoSizer, VirtualTableBody } from '@patternfly/react-virtualized-extension'; -export const SortableExample: React.FunctionComponent = () => { +export const SortableExample: FunctionComponent = () => { const rows: { id: string; cells: string[] }[] = []; for (let i = 0; i < 100; i++) { rows.push({ @@ -14,10 +15,10 @@ export const SortableExample: React.FunctionComponent = () => { const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last Commit']; - const [activeSortIndex, setActiveSortIndex] = React.useState(-1); + const [activeSortIndex, setActiveSortIndex] = useState(-1); // Sort direction of the currently sorted column - const [activeSortDirection, setActiveSortDirection] = React.useState<'asc' | 'desc' | undefined>(); + const [activeSortDirection, setActiveSortDirection] = useState<'asc' | 'desc' | undefined>(); const getRowIndex = (str: string) => Number(str?.split('-')[1]); diff --git a/packages/module/patternfly-docs/content/examples/WindowScroller.tsx b/packages/module/patternfly-docs/content/examples/WindowScroller.tsx index 363237a..213487f 100644 --- a/packages/module/patternfly-docs/content/examples/WindowScroller.tsx +++ b/packages/module/patternfly-docs/content/examples/WindowScroller.tsx @@ -1,11 +1,11 @@ -import React from 'react'; +import { useState, useEffect } from 'react'; import { CellMeasurerCache, CellMeasurer } from 'react-virtualized'; import { AutoSizer, VirtualTableBody, WindowScroller } from '@patternfly/react-virtualized-extension'; import { Table, Thead, Tr, Th, Td, Caption, TableGridBreakpoint } from '@patternfly/react-table'; export const WindowScrollerExample = () => { - const [scrollableElement, setScrollableElement] = React.useState(); - React.useEffect(() => { + const [scrollableElement, setScrollableElement] = useState(); + useEffect(() => { const scrollableElement = document.getElementById('content-scrollable-2') as HTMLElement; setScrollableElement(scrollableElement); }, []); diff --git a/packages/module/patternfly-docs/generated/extensions/virtual-scroll-table/react.js b/packages/module/patternfly-docs/generated/extensions/virtual-scroll-table/react.js index 9b06e77..b93230f 100644 --- a/packages/module/patternfly-docs/generated/extensions/virtual-scroll-table/react.js +++ b/packages/module/patternfly-docs/generated/extensions/virtual-scroll-table/react.js @@ -1,4 +1,4 @@ -import React from 'react'; +import { createElement, Fragment } from 'react'; import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon'; import FilterIcon from '@patternfly/react-icons/dist/esm/icons/filter-icon'; @@ -216,7 +216,7 @@ pageData.examples = { }; const Component = () => ( - +

{`Note: React Virtualized Extension lives in its own package at `} @@ -229,12 +229,12 @@ const Component = () => ( {`Examples`} - {React.createElement(pageData.examples["Basic"])} - {React.createElement(pageData.examples["Sortable"])} - {React.createElement(pageData.examples["Selectable"])} - {React.createElement(pageData.examples["Actions"])} - {React.createElement(pageData.examples["Filterable with WindowScroller"])} - + {createElement(pageData.examples["Basic"])} + {createElement(pageData.examples["Sortable"])} + {createElement(pageData.examples["Selectable"])} + {createElement(pageData.examples["Actions"])} + {createElement(pageData.examples["Filterable with WindowScroller"])} + ); Component.displayName = 'ExtensionsVirtualScrollTableReactDocs'; Component.pageData = pageData; diff --git a/packages/module/patternfly-docs/generated/extensions/virtual-scroll-window-scroller/react.js b/packages/module/patternfly-docs/generated/extensions/virtual-scroll-window-scroller/react.js index 732f925..25ff0ce 100644 --- a/packages/module/patternfly-docs/generated/extensions/virtual-scroll-window-scroller/react.js +++ b/packages/module/patternfly-docs/generated/extensions/virtual-scroll-window-scroller/react.js @@ -1,4 +1,4 @@ -import React from 'react'; +import { createElement, Fragment } from 'react'; import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; import { CellMeasurerCache, CellMeasurer } from 'react-virtualized'; import { AutoSizer, VirtualTableBody, WindowScroller } from '@patternfly/react-virtualized-extension'; @@ -185,7 +185,7 @@ pageData.examples = { }; const Component = () => ( - +

{`Note: React Virtualized Extension lives in its own package at `} @@ -207,8 +207,8 @@ This package is currently an extension. Extension components do not undergo the {`Examples`} - {React.createElement(pageData.examples["Window scroller"])} - + {createElement(pageData.examples["Window scroller"])} + ); Component.displayName = 'ExtensionsVirtualScrollWindowScrollerReactDocs'; Component.pageData = pageData; diff --git a/packages/module/patternfly-docs/generated/react.js b/packages/module/patternfly-docs/generated/react.js index c4f2481..4e9271e 100644 --- a/packages/module/patternfly-docs/generated/react.js +++ b/packages/module/patternfly-docs/generated/react.js @@ -1,4 +1,4 @@ -import React from 'react'; +import { createElement, Fragment } from 'react'; import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; import { ExtendedButton } from "@patternfly/react-virtualized-extension"; const pageData = { @@ -45,13 +45,13 @@ pageData.examples = { }; const Component = () => ( - + {`Basic usage`} - {React.createElement(pageData.examples["Example"])} - {React.createElement(pageData.examples["Fullscreen example"])} - + {createElement(pageData.examples["Example"])} + {createElement(pageData.examples["Fullscreen example"])} + ); Component.displayName = 'ExtensionsPatternflyExtensionSeedReactDocs'; Component.pageData = pageData; diff --git a/packages/module/patternfly-docs/pages/index.js b/packages/module/patternfly-docs/pages/index.js index 54c2430..d734ac4 100644 --- a/packages/module/patternfly-docs/pages/index.js +++ b/packages/module/patternfly-docs/pages/index.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Title, PageSection } from '@patternfly/react-core'; const centerStyle = { diff --git a/packages/module/src/components/Virtualized/VirtualGrid.ts b/packages/module/src/components/Virtualized/VirtualGrid.ts index 0d9902a..ac93940 100644 --- a/packages/module/src/components/Virtualized/VirtualGrid.ts +++ b/packages/module/src/components/Virtualized/VirtualGrid.ts @@ -1,5 +1,7 @@ /* eslint-disable */ -import * as React from 'react'; +import type { ComponentType, ReactElement } from 'react'; + +import { createElement, Component } from 'react'; import calculateSizeAndPositionDataAndUpdateScrollOffset from './utils/calculateSizeAndPositionDataAndUpdateScrollOffset'; import ScalingCellSizeAndPositionManager from './utils/ScalingCellSizeAndPositionManager'; import createCallbackMemoizer from './utils/createCallbackMemoizer'; @@ -233,10 +235,10 @@ export interface VirtualGridProps { width: number; /** Scroll Container element to render */ - scrollContainerComponent?: string | React.ComponentType; + scrollContainerComponent?: string | ComponentType; /** Inner Scroll Container element to render */ - innerScrollContainerComponent?: string | React.ComponentType; + innerScrollContainerComponent?: string | ComponentType; } interface InstanceProps { @@ -271,7 +273,7 @@ interface VirtualGridState { * Renders tabular data with virtualization along the vertical and horizontal axes. * Row heights and column widths must be known ahead of time and specified as properties. */ -export class VirtualGrid extends React.Component { +export class VirtualGrid extends Component { static defaultProps = { 'aria-label': 'grid', 'aria-readonly': true, @@ -317,7 +319,7 @@ export class VirtualGrid extends React.Component[]; + _childrenToDisplay: ReactElement[]; _columnStartIndex: number; _columnStopIndex: number; @@ -1020,13 +1022,13 @@ export class VirtualGrid extends React.Component { +export class VirtualTableBody extends Component { static defaultProps = { autoHeight: false, estimatedRowSize: 30, @@ -232,7 +232,7 @@ export class VirtualTableBody extends React.Component { // note: these aria props if rendered will break a11y for role="presentation" // this approach attempts to fix non standard table grids // see: https://www.html5accessibility.com/tests/aria-table-fix.html - { scrollToRow={scrollToIndex} scrollContainerComponent={scrollContainerComponent} innerScrollContainerComponent={innerScrollContainerComponent} - /> + />) ); } diff --git a/packages/module/src/components/Virtualized/VirtualizedTable.test.tsx b/packages/module/src/components/Virtualized/VirtualizedTable.test.tsx index 67b1a51..8346972 100644 --- a/packages/module/src/components/Virtualized/VirtualizedTable.test.tsx +++ b/packages/module/src/components/Virtualized/VirtualizedTable.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { sortable diff --git a/packages/module/src/components/Virtualized/testDataSets.tsx b/packages/module/src/components/Virtualized/testDataSets.tsx index a6334ad..2a3d4be 100644 --- a/packages/module/src/components/Virtualized/testDataSets.tsx +++ b/packages/module/src/components/Virtualized/testDataSets.tsx @@ -2,7 +2,7 @@ // This file is test data pulled from the @patternfly/react-table package -import * as React from 'react'; +import type { MouseEvent } from 'react'; import { IRow, ICell, IActions, EditableTextCell } from '@patternfly/react-table'; export const columns: (ICell | string)[] = [ @@ -198,13 +198,13 @@ export const editableRows: IRow[] = [ export const actions: IActions = [ { title: 'Some action', - onClick: (event: React.MouseEvent, rowId: number) => + onClick: (event: MouseEvent, rowId: number) => // tslint:disable-next-line:no-console console.log('clicked on Some action, on row: ', rowId) }, { title:

Another action
, - onClick: (event: React.MouseEvent, rowId: number) => + onClick: (event: MouseEvent, rowId: number) => // tslint:disable-next-line:no-console console.log('clicked on Another action, on row: ', rowId) }, @@ -214,7 +214,7 @@ export const actions: IActions = [ }, { title: 'Third action', - onClick: (event: React.MouseEvent, rowId: number) => + onClick: (event: MouseEvent, rowId: number) => // tslint:disable-next-line:no-console console.log('clicked on Third action, on row: ', rowId) } diff --git a/packages/module/src/components/Virtualized/types.ts b/packages/module/src/components/Virtualized/types.ts index 36a65cd..e6dbea2 100644 --- a/packages/module/src/components/Virtualized/types.ts +++ b/packages/module/src/components/Virtualized/types.ts @@ -1,4 +1,4 @@ -import * as React from 'react'; +import type { ReactElement } from 'react'; import ScalingCellSizeAndPositionManager from './utils/ScalingCellSizeAndPositionManager'; export interface CellPosition { @@ -16,10 +16,10 @@ export interface CellRendererParams { style: any; } -export type CellRenderer = (props: CellRendererParams) => React.ReactElement; +export type CellRenderer = (props: CellRendererParams) => ReactElement; export interface CellCache { - [key: string]: React.ReactElement; + [key: string]: ReactElement; } export interface StyleCache { [key: string]: any; @@ -47,13 +47,13 @@ export interface CellRangeRendererParams { visibleRowIndices: any; } -export type CellRangeRenderer = (params: CellRangeRendererParams) => React.ReactElement[]; +export type CellRangeRenderer = (params: CellRangeRendererParams) => ReactElement[]; export type CellSizeGetter = (params: { index: number }) => number; export type CellSize = CellSizeGetter | number; -export type NoContentRenderer = () => React.ReactElement | null; +export type NoContentRenderer = () => ReactElement | null; export interface Scroll { clientHeight: number; diff --git a/packages/module/tsconfig.json b/packages/module/tsconfig.json index bd3e41a..f0fa037 100644 --- a/packages/module/tsconfig.json +++ b/packages/module/tsconfig.json @@ -9,7 +9,7 @@ "lib": ["es2015", "dom"], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ - "jsx": "react" /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */, + "jsx": "react-jsx" /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */, // "declaration": true /* Generates corresponding '.d.ts' file. */, "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ "sourceMap": true, /* Generates corresponding '.map' file. */ From 301e0c4b10d18555c13fd2848426aec72c96f832 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Thu, 5 Jun 2025 15:29:59 -0400 Subject: [PATCH 2/4] Try to fix runner --- .github/workflows/build-lint-test.yml | 44 +++++++++++++-------------- .github/workflows/build.yml | 12 ++++---- .github/workflows/promote.yml | 4 +-- .github/workflows/release.yml | 12 ++++---- 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/.github/workflows/build-lint-test.yml b/.github/workflows/build-lint-test.yml index 806c45b..ca2d66e 100644 --- a/.github/workflows/build-lint-test.yml +++ b/.github/workflows/build-lint-test.yml @@ -7,7 +7,7 @@ jobs: env: GH_PR_NUM: ${{ github.event.number }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - run: | if [[ ! -z "${GH_PR_NUM}" ]]; then echo "Checking out PR" @@ -17,17 +17,17 @@ jobs: - uses: actions/setup-node@v1 with: node-version: '20' - - uses: actions/cache@v2 + - uses: actions/cache@v4 id: yarn-cache name: Cache npm deps with: path: | - node_modules - **/node_modules + node_modules + **/node_modules key: ${{ runner.os }}-yarn-14-${{ secrets.CACHE_VERSION }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile if: steps.yarn-cache.outputs.cache-hit != 'true' - - uses: actions/cache@v2 + - uses: actions/cache@v4 id: dist name: Cache dist with: @@ -43,7 +43,7 @@ jobs: GH_PR_NUM: ${{ github.event.number }} needs: build steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - run: | if [[ ! -z "${GH_PR_NUM}" ]]; then echo "Checking out PR" @@ -53,17 +53,17 @@ jobs: - uses: actions/setup-node@v1 with: node-version: '20' - - uses: actions/cache@v2 + - uses: actions/cache@v4 id: yarn-cache name: Cache npm deps with: path: | - node_modules - **/node_modules + node_modules + **/node_modules key: ${{ runner.os }}-yarn-14-${{ secrets.CACHE_VERSION }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile if: steps.yarn-cache.outputs.cache-hit != 'true' - - uses: actions/cache@v2 + - uses: actions/cache@v4 id: lint-cache name: Load lint cache with: @@ -79,7 +79,7 @@ jobs: GH_PR_NUM: ${{ github.event.number }} needs: build steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # Yes, we really want to checkout the PR - run: | if [[ ! -z "${GH_PR_NUM}" ]]; then @@ -90,18 +90,18 @@ jobs: - uses: actions/setup-node@v1 with: node-version: '20' - - uses: actions/cache@v2 + - uses: actions/cache@v4 id: yarn-cache name: Cache npm deps with: path: | - node_modules - **/node_modules - ~/.cache/Cypress + node_modules + **/node_modules + ~/.cache/Cypress key: ${{ runner.os }}-yarn-14-${{ secrets.CACHE_VERSION }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile if: steps.yarn-cache.outputs.cache-hit != 'true' - - uses: actions/cache@v2 + - uses: actions/cache@v4 id: dist name: Cache dist with: @@ -120,7 +120,7 @@ jobs: GH_PR_NUM: ${{ github.event.number }} needs: build steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # Yes, we really want to checkout the PR - run: | if [[ ! -z "${GH_PR_NUM}" ]]; then @@ -131,18 +131,18 @@ jobs: - uses: actions/setup-node@v1 with: node-version: '20' - - uses: actions/cache@v2 + - uses: actions/cache@v4 id: yarn-cache name: Cache npm deps with: path: | - node_modules - **/node_modules - ~/.cache/Cypress + node_modules + **/node_modules + ~/.cache/Cypress key: ${{ runner.os }}-yarn-14-${{ secrets.CACHE_VERSION }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile if: steps.yarn-cache.outputs.cache-hit != 'true' - - uses: actions/cache@v2 + - uses: actions/cache@v4 id: dist name: Cache dist with: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d149512..7712bf4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,14 +7,14 @@ jobs: env: GH_PR_NUM: ${{ github.event.number }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - run: | if [[ ! -z "${GH_PR_NUM}" ]]; then echo "Checking out PR" git fetch origin pull/$GH_PR_NUM/head:tmp git checkout tmp fi - - uses: actions/cache@v2 + - uses: actions/cache@v4 id: setup-cache name: Cache setup with: @@ -33,17 +33,17 @@ jobs: - uses: actions/setup-node@v1 with: node-version: '20' - - uses: actions/cache@v2 + - uses: actions/cache@v4 id: yarn-cache name: Cache npm deps with: path: | - node_modules - **/node_modules + node_modules + **/node_modules key: ${{ runner.os }}-yarn-14-${{ secrets.CACHE_VERSION }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile if: steps.yarn-cache.outputs.cache-hit != 'true' - - uses: actions/cache@v2 + - uses: actions/cache@v4 id: dist name: Cache dist with: diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml index 28fa19e..54026e7 100644 --- a/.github/workflows/promote.yml +++ b/.github/workflows/promote.yml @@ -2,7 +2,7 @@ name: promote on: push: # Sequence of patterns matched against refs/tags - tags: + tags: - v6.* jobs: build-and-promote: @@ -12,7 +12,7 @@ jobs: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Build for promotion run: yarn install --frozen-lockfile && yarn build - uses: actions/setup-node@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d7fb3fa..a029caa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,22 +13,22 @@ jobs: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: actions/setup-node@v1 with: node-version: '20' - - uses: actions/cache@v2 + - uses: actions/cache@v4 id: yarn-cache name: Cache npm deps with: path: | - node_modules - **/node_modules - ~/.cache/Cypress + node_modules + **/node_modules + ~/.cache/Cypress key: ${{ runner.os }}-yarn-14-${{ secrets.CACHE_VERSION }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile if: steps.yarn-cache.outputs.cache-hit != 'true' - - uses: actions/cache@v2 + - uses: actions/cache@v4 id: dist name: Cache dist with: From 48bce3ed21583b3b6c9160217adeb671dec59fd5 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Thu, 5 Jun 2025 15:52:16 -0400 Subject: [PATCH 3/4] Fix test errors --- .eslintrc.json | 3 ++- babel.config.js | 9 +++++++-- package.json | 4 ++-- packages/module/patternfly-docs/pages/index.js | 4 +++- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index bf7d11e..64cea08 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -94,6 +94,7 @@ "react-hooks/exhaustive-deps": "warn", "react/no-unescaped-entities": ["error", { "forbid": [">", "}"] }], "spaced-comment": "error", - "use-isnan": "error" + "use-isnan": "error", + "react/react-in-jsx-scope": "off" } } diff --git a/babel.config.js b/babel.config.js index 5aac1c4..52a9841 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,8 +1,13 @@ module.exports = { presets: [ ['@babel/preset-env', { targets: { esmodules: true } }], - '@babel/preset-react', + [ + '@babel/preset-react', + { + runtime: 'automatic' + } + ], '@babel/preset-flow', '@babel/preset-typescript' ] -}; \ No newline at end of file +}; diff --git a/package.json b/package.json index 2a3a96d..f7c6ab4 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,8 @@ "serve:a11y": "yarn workspace @patternfly/react-virtualized-extension serve:a11y" }, "devDependencies": { - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0", "typescript": "^5.0.4", "@types/react": "^18.2.7", "@types/react-dom": "^18.2.4", diff --git a/packages/module/patternfly-docs/pages/index.js b/packages/module/patternfly-docs/pages/index.js index d734ac4..a6f0cc7 100644 --- a/packages/module/patternfly-docs/pages/index.js +++ b/packages/module/patternfly-docs/pages/index.js @@ -1,3 +1,5 @@ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import React from 'react'; import { Title, PageSection } from '@patternfly/react-core'; const centerStyle = { @@ -9,7 +11,7 @@ const centerStyle = { const IndexPage = () => { return ( - +
My extension docs From 14f1ee08b52e5b857c88f65224e98b2f6b537158 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert <ralpert@redhat.com> Date: Thu, 5 Jun 2025 16:03:13 -0400 Subject: [PATCH 4/4] Fix examples --- .gitignore | 1 + package.json | 4 +- .../content/examples/Selectable.tsx | 3 +- .../content/examples/Sortable.tsx | 3 +- .../content/examples/VirtualizedTable.md | 6 + .../content/examples/WindowScroller.md | 2 + .../extensions/virtual-scroll-table/react.js | 242 ------------------ .../virtual-scroll-window-scroller/react.js | 216 ---------------- .../module/patternfly-docs/generated/index.js | 24 -- .../module/patternfly-docs/generated/react.js | 59 ----- .../components/Virtualized/testDataSets.tsx | 8 +- yarn.lock | 22 +- 12 files changed, 28 insertions(+), 562 deletions(-) delete mode 100644 packages/module/patternfly-docs/generated/extensions/virtual-scroll-table/react.js delete mode 100644 packages/module/patternfly-docs/generated/extensions/virtual-scroll-window-scroller/react.js delete mode 100644 packages/module/patternfly-docs/generated/index.js delete mode 100644 packages/module/patternfly-docs/generated/react.js diff --git a/.gitignore b/.gitignore index e61a201..a628326 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ coverage .cache .tmp .eslintcache +generated # package managers yarn-error.log diff --git a/package.json b/package.json index f7c6ab4..2a3a96d 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,8 @@ "serve:a11y": "yarn workspace @patternfly/react-virtualized-extension serve:a11y" }, "devDependencies": { - "react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0", "typescript": "^5.0.4", "@types/react": "^18.2.7", "@types/react-dom": "^18.2.4", diff --git a/packages/module/patternfly-docs/content/examples/Selectable.tsx b/packages/module/patternfly-docs/content/examples/Selectable.tsx index 7e5469e..afe1789 100644 --- a/packages/module/patternfly-docs/content/examples/Selectable.tsx +++ b/packages/module/patternfly-docs/content/examples/Selectable.tsx @@ -1,5 +1,4 @@ -import { FunctionComponent } from 'react'; -import { useState } from 'react'; +import { FunctionComponent, useState } from 'react'; import { CellMeasurerCache, CellMeasurer } from 'react-virtualized'; import { AutoSizer, VirtualTableBody } from '@patternfly/react-virtualized-extension'; diff --git a/packages/module/patternfly-docs/content/examples/Sortable.tsx b/packages/module/patternfly-docs/content/examples/Sortable.tsx index b0b05de..7ef3fa4 100644 --- a/packages/module/patternfly-docs/content/examples/Sortable.tsx +++ b/packages/module/patternfly-docs/content/examples/Sortable.tsx @@ -1,5 +1,4 @@ -import type { FunctionComponent } from 'react'; -import { useState } from 'react'; +import { useState, FunctionComponent } from 'react'; import { Caption, Table, Td, Th, Thead, ThProps, Tr } from '@patternfly/react-table'; import { CellMeasurerCache, CellMeasurer } from 'react-virtualized'; import { AutoSizer, VirtualTableBody } from '@patternfly/react-virtualized-extension'; diff --git a/packages/module/patternfly-docs/content/examples/VirtualizedTable.md b/packages/module/patternfly-docs/content/examples/VirtualizedTable.md index 524952c..ebcb235 100644 --- a/packages/module/patternfly-docs/content/examples/VirtualizedTable.md +++ b/packages/module/patternfly-docs/content/examples/VirtualizedTable.md @@ -15,30 +15,36 @@ import { AutoSizer, VirtualTableBody, WindowScroller } from '@patternfly/react-v import { Table as TableDeprecated, TableHeader as TableHeaderDeprecated } from '@patternfly/react-table/deprecated'; import { Table, Thead, Tr, Th, Td, Caption, TableGridBreakpoint } from '@patternfly/react-table'; import './VirtualGrid.example.css'; +import { useState, useEffect, Fragment } from 'react'; ## Examples ### Basic ```js file="./Basic.tsx" + ``` ### Sortable ```js file="./Sortable.tsx" + ``` ### Selectable ```js file="./Selectable.tsx" + ``` ### Actions ```js file="./Actions.tsx" + ``` ### Filterable with WindowScroller ```js file="./FilterableWithWindowScroller.tsx" + ``` diff --git a/packages/module/patternfly-docs/content/examples/WindowScroller.md b/packages/module/patternfly-docs/content/examples/WindowScroller.md index 8e47f9b..5c43e97 100644 --- a/packages/module/patternfly-docs/content/examples/WindowScroller.md +++ b/packages/module/patternfly-docs/content/examples/WindowScroller.md @@ -17,10 +17,12 @@ import { AutoSizer, VirtualTableBody, WindowScroller } from '@patternfly/react-v import { Table as TableDeprecated, TableHeader as TableHeaderDeprecated } from '@patternfly/react-table/deprecated'; import './VirtualGrid.example.css'; import './WindowScroller.example.css'; +import { useState, useEffect } from 'react'; ## Examples ### Window scroller ```js file="WindowScroller.tsx" + ``` diff --git a/packages/module/patternfly-docs/generated/extensions/virtual-scroll-table/react.js b/packages/module/patternfly-docs/generated/extensions/virtual-scroll-table/react.js deleted file mode 100644 index b93230f..0000000 --- a/packages/module/patternfly-docs/generated/extensions/virtual-scroll-table/react.js +++ /dev/null @@ -1,242 +0,0 @@ -import { createElement, Fragment } from 'react'; -import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; -import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon'; -import FilterIcon from '@patternfly/react-icons/dist/esm/icons/filter-icon'; -import { CellMeasurerCache, CellMeasurer} from 'react-virtualized'; -import { AutoSizer, VirtualTableBody, WindowScroller } from '@patternfly/react-virtualized-extension'; -import { Table as TableDeprecated, TableHeader as TableHeaderDeprecated } from '@patternfly/react-table/deprecated'; -import { Table, Thead, Tr, Th, Td, Caption, TableGridBreakpoint } from '@patternfly/react-table'; -import '../../../content/examples/./VirtualGrid.example.css'; -const pageData = { - "id": "Virtual scroll table", - "section": "extensions", - "subsection": "", - "deprecated": false, - "template": false, - "beta": false, - "demo": false, - "newImplementationLink": false, - "source": "react", - "tabName": null, - "slug": "/extensions/virtual-scroll-table/react", - "sourceLink": "https://github.com/patternfly/react-virtualized-extension", - "relPath": "packages/module/patternfly-docs/content/examples/VirtualizedTable.md", - "propComponents": [ - { - "name": "VirtualTableBody", - "description": "It is inefficient to create and manage a large list of DOM elements within a scrolling container\nif only a few of those elements are visible. The primary purpose of this component is to improve\nperformance by only rendering the DOM nodes that a user is able to see based on their current\nscroll position.\n\nThis component renders a virtualized list of elements with either fixed or dynamic heights.", - "props": [ - { - "name": "aria-label", - "type": "string", - "description": "" - }, - { - "name": "autoHeight", - "type": "boolean", - "description": "Removes fixed height from the scrollingContainer so that the total height\nof rows can stretch the window. Intended for use with WindowScroller", - "defaultValue": "false" - }, - { - "name": "className", - "type": "string", - "description": "Optional CSS class name" - }, - { - "name": "columnCount", - "type": "number", - "description": "" - }, - { - "name": "columns", - "type": "any[]", - "description": "" - }, - { - "name": "estimatedRowSize", - "type": "number", - "description": "Used to estimate the total height of a List before all of its rows have actually been measured.\nThe estimated total height is adjusted as rows are rendered.", - "defaultValue": "30" - }, - { - "name": "height", - "type": "number", - "description": "Height constraint for list (determines how many actual rows are rendered)", - "required": true - }, - { - "name": "innerScrollContainerComponent", - "type": "No type info", - "defaultValue": "'tbody'" - }, - { - "name": "noRowsRenderer", - "type": "NoContentRenderer", - "description": "Optional renderer to be used in place of rows when rowCount is 0", - "defaultValue": "() => null as any" - }, - { - "name": "onRowsRendered", - "type": "(params: any) => void", - "description": "Callback invoked with information about the slice of rows that were just rendered.", - "defaultValue": "() => {}" - }, - { - "name": "onScroll", - "type": "(params: Scroll) => void", - "description": "Callback invoked whenever the scroll offset changes within the inner scrollable region.\nThis callback can be used to sync scrolling between lists, tables, or grids.", - "defaultValue": "() => {}" - }, - { - "name": "overscanIndicesGetter", - "type": "OverscanIndicesGetter", - "description": "See VirtualGrid#overscanIndicesGetter", - "defaultValue": "accessibilityOverscanIndicesGetter" - }, - { - "name": "overscanRowCount", - "type": "number", - "description": "Number of rows to render above/below the visible bounds of the list.\nThese rows can help for smoother scrolling on touch devices.", - "defaultValue": "10" - }, - { - "name": "rowCount", - "type": "number", - "description": "Number of rows in list.", - "required": true - }, - { - "name": "rowHeight", - "type": "CellSize", - "description": "Either a fixed row height (number) or a function that returns the height of a row given its index.", - "required": true - }, - { - "name": "rowRenderer", - "type": "any", - "description": "Responsible for rendering a row given an index; ({ index: number }): node", - "required": true - }, - { - "name": "rows", - "type": "any[]", - "description": "", - "required": true - }, - { - "name": "scrollContainerComponent", - "type": "No type info", - "defaultValue": "'table'" - }, - { - "name": "scrollToAlignment", - "type": "Alignment", - "description": "See VirtualGrid#scrollToAlignment", - "defaultValue": "'auto'" - }, - { - "name": "scrollToIndex", - "type": "number", - "description": "Row index to ensure visible (by forcefully scrolling if necessary)", - "defaultValue": "-1" - }, - { - "name": "scrollTop", - "type": "number", - "description": "Vertical offset." - }, - { - "name": "style", - "type": "Object", - "description": "", - "defaultValue": "{}" - }, - { - "name": "tabIndex", - "type": "number", - "description": "Tab index for focus" - }, - { - "name": "width", - "type": "number", - "description": "Width of list", - "required": true - } - ] - } - ], - "examples": [ - "Basic", - "Sortable", - "Selectable", - "Actions", - "Filterable with WindowScroller" - ] -}; -pageData.liveContext = { - SearchIcon, - FilterIcon, - CellMeasurerCache, - CellMeasurer, - AutoSizer, - VirtualTableBody, - WindowScroller, - TableDeprecated, - TableHeaderDeprecated, - Table, - Thead, - Tr, - Th, - Td, - Caption, - TableGridBreakpoint -}; -pageData.relativeImports = "import 'content/examples/./VirtualGrid.example.css';" -pageData.examples = { - 'Basic': props => - <Example {...pageData} {...props} {...{"code":"import React from 'react';\nimport { Caption, Table, TableGridBreakpoint, Td, Th, Thead, Tr } from '@patternfly/react-table';\nimport { CellMeasurerCache, CellMeasurer } from 'react-virtualized';\nimport { AutoSizer, VirtualTableBody } from '@patternfly/react-virtualized-extension';\n\nexport const VirtualizedExample: React.FunctionComponent = () => {\n // this StringArray type is just needed because something in our documentation framework crashes when it encounters\n // a string[][] type\n type StringArray = string[];\n const rows: StringArray[] = [];\n for (let i = 0; i < 100; i++) {\n rows.push([`one-${i}`, `two-${i}`, `three-${i}`, `four-${i}`, `five-${i}`]);\n }\n\n const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last Commit'];\n\n const measurementCache = new CellMeasurerCache({\n fixedWidth: true,\n minHeight: 44,\n keyMapper: (rowIndex) => rowIndex\n });\n\n const rowRenderer = ({ index: rowIndex, _isScrolling, key, style, parent }) => (\n <CellMeasurer cache={measurementCache} columnIndex={0} key={key} parent={parent} rowIndex={rowIndex}>\n <Tr style={style}>\n {columns.map((col, index) => (\n <Td key={`${rowIndex}-${index + 1}`}>{rows[rowIndex][index]}</Td>\n ))}\n </Tr>\n </CellMeasurer>\n );\n\n return (\n <div aria-label=\"Scrollable Table\" className=\"pf-v6-c-scrollablegrid\">\n <Table gridBreakPoint={TableGridBreakpoint.none} aria-rowcount={rows.length}>\n <Caption>Simple Table</Caption>\n <Thead>\n <Tr>\n {columns.map((col, index) => (\n <Th key={++index}>{col}</Th>\n ))}\n </Tr>\n </Thead>\n </Table>\n <AutoSizer disableHeight>\n {({ width }) => (\n <VirtualTableBody\n className=\"pf-v6-c-table pf-v6-c-virtualized pf-v6-c-window-scroller\"\n deferredMeasurementCache={measurementCache}\n rowHeight={measurementCache.rowHeight}\n height={400}\n overscanRowCount={2}\n columnCount={1}\n rows={rows}\n rowCount={rows.length}\n rowRenderer={rowRenderer}\n width={width}\n role=\"grid\"\n />\n )}\n </AutoSizer>\n </div>\n );\n};\n","title":"Basic","lang":"js","className":""}}> - - </Example>, - 'Sortable': props => - <Example {...pageData} {...props} {...{"code":"import React from 'react';\nimport { Caption, Table, Td, Th, Thead, ThProps, Tr } from '@patternfly/react-table';\nimport { CellMeasurerCache, CellMeasurer } from 'react-virtualized';\nimport { AutoSizer, VirtualTableBody } from '@patternfly/react-virtualized-extension';\n\nexport const SortableExample: React.FunctionComponent = () => {\n const rows: { id: string; cells: string[] }[] = [];\n for (let i = 0; i < 100; i++) {\n rows.push({\n id: `sortable-row-${i}`,\n cells: [`one-${i}`, `two-${i}`, `three-${i}`, `four-${i}`, `five-${i}`]\n });\n }\n\n const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last Commit'];\n\n const [activeSortIndex, setActiveSortIndex] = React.useState<number>(-1);\n\n // Sort direction of the currently sorted column\n const [activeSortDirection, setActiveSortDirection] = React.useState<'asc' | 'desc' | undefined>();\n\n const getRowIndex = (str: string) => Number(str?.split('-')[1]);\n\n const getSortParams = (columnIndex: number): ThProps['sort'] => ({\n sortBy: {\n index: activeSortIndex,\n direction: activeSortDirection\n },\n onSort: (_event, index, direction) => {\n setActiveSortIndex(index);\n setActiveSortDirection(direction as 'desc' | 'asc');\n },\n columnIndex\n });\n\n if (activeSortIndex !== null) {\n rows.sort((a, b) => {\n const aValue = a.cells[activeSortIndex];\n const bValue = b.cells[activeSortIndex];\n\n const aValueIndex = getRowIndex(aValue);\n const bValueIndex = getRowIndex(bValue);\n\n if (activeSortDirection === 'asc') {\n return aValueIndex - bValueIndex;\n }\n\n return bValueIndex - aValueIndex;\n });\n }\n\n const measurementCache = new CellMeasurerCache({\n fixedWidth: true,\n minHeight: 44,\n keyMapper: (rowIndex) => rowIndex\n });\n\n const rowRenderer = ({ index: rowIndex, _isScrolling, key, style, parent }) => (\n <CellMeasurer cache={measurementCache} columnIndex={0} key={key} parent={parent} rowIndex={rowIndex}>\n <Tr style={style}>\n {columns.map((col, index) => (\n <Td key={`${rowIndex}-${index + 1}`}>{rows[rowIndex].cells[index]}</Td>\n ))}\n </Tr>\n </CellMeasurer>\n );\n return (\n <div aria-label=\"Scrollable Table\" className=\"pf-v6-c-scrollablegrid\">\n <Table aria-label=\"Sortable table\" ouiaId=\"SortableTable\">\n <Caption>Sortable Virtualized Table</Caption>\n <Thead>\n <Tr>\n <Th sort={getSortParams(0)}>{columns[0]}</Th>\n <Th>{columns[1]}</Th>\n <Th sort={getSortParams(2)}>{columns[2]}</Th>\n <Th>{columns[3]}</Th>\n <Th>{columns[4]}</Th>\n </Tr>\n </Thead>\n </Table>\n <AutoSizer disableHeight>\n {({ width }) => (\n <VirtualTableBody\n ref={(ref) => ref}\n className=\"pf-v6-c-table pf-v6-c-virtualized pf-v6-c-window-scroller\"\n deferredMeasurementCache={measurementCache}\n rowHeight={measurementCache.rowHeight}\n height={400}\n overscanRowCount={2}\n columnCount={1}\n rows={rows}\n rowCount={rows.length}\n rowRenderer={rowRenderer}\n width={width}\n role=\"grid\"\n />\n )}\n </AutoSizer>\n </div>\n );\n};\n","title":"Sortable","lang":"js","className":""}}> - - </Example>, - 'Selectable': props => - <Example {...pageData} {...props} {...{"code":"import React from 'react';\n\nimport { CellMeasurerCache, CellMeasurer } from 'react-virtualized';\nimport { AutoSizer, VirtualTableBody } from '@patternfly/react-virtualized-extension';\nimport { Table, Thead, Tr, Th, Td, Caption, TableGridBreakpoint } from '@patternfly/react-table';\n\nexport const SelectableTableVirtualized: React.FunctionComponent = () => {\n // this StringArray type is just needed because something in our documentation framework crashes when it encounters\n // a string[][] type\n type StringArray = string[];\n const rows: StringArray[] = [];\n\n for (let i = 0; i < 100; i++) {\n rows.push([`one-${i}`, `two-${i}`, `three-${i}`, `four-${i}`, `five-${i}`]);\n }\n\n const selectableRepos = rows;\n\n const [selectedRepoNames, setSelectedRepoNames] = React.useState<string[]>([]);\n\n const setRepoSelected = (repo: string, isSelecting = true) =>\n setSelectedRepoNames((prevSelected) => {\n const otherSelectedRepoNames = prevSelected.filter((r) => r !== repo);\n return isSelecting ? [...otherSelectedRepoNames, repo] : otherSelectedRepoNames;\n });\n\n const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last Commit'];\n\n const selectAllRepos = (isSelecting = true) => setSelectedRepoNames(isSelecting ? rows.map((item) => item[0]) : []);\n\n const areAllReposSelected = selectedRepoNames.length === selectableRepos.length;\n const isRepoSelected = (repo: string) => selectedRepoNames.includes(repo);\n\n const [recentSelectedRowIndex, setRecentSelectedRowIndex] = React.useState<number | null>(null);\n\n const onSelectRepo = (repo: string, rowIndex: number, isSelecting: boolean) => {\n if (recentSelectedRowIndex !== null) {\n const numberSelected = rowIndex - recentSelectedRowIndex;\n const intermediateIndexes =\n numberSelected > 0\n ? Array.from(new Array(numberSelected + 1), (_x, i) => i + recentSelectedRowIndex)\n : Array.from(new Array(Math.abs(numberSelected) + 1), (_x, i) => i + rowIndex);\n intermediateIndexes.forEach(() => setRepoSelected(repo, isSelecting));\n } else {\n setRepoSelected(repo, isSelecting);\n }\n setRecentSelectedRowIndex(rowIndex);\n };\n\n const measurementCache = new CellMeasurerCache({\n fixedWidth: true,\n minHeight: 44,\n keyMapper: (rowIndex) => rowIndex\n });\n\n const rowRenderer = ({ index: rowIndex, _isScrolling, key, style, parent }) => (\n <CellMeasurer cache={measurementCache} columnIndex={0} key={key} parent={parent} rowIndex={rowIndex}>\n <Tr style={style}>\n <Td\n key={`${rowIndex}_0`}\n select={{\n rowIndex,\n onSelect: (_event, isSelecting) => onSelectRepo(rows[rowIndex][0], rowIndex, isSelecting),\n isSelected: isRepoSelected(rows[rowIndex][0])\n }}\n />\n {columns.map((col, index) => (\n <Td key={`${rowIndex}-${index + 1}`}>{rows[rowIndex][index]}</Td>\n ))}\n </Tr>\n </CellMeasurer>\n );\n\n return (\n <div aria-label=\"Scrollable Table\" className=\"pf-v6-c-scrollablegrid\">\n <Table gridBreakPoint={TableGridBreakpoint.none} aria-rowcount={rows.length}>\n <Caption>Selectable Virtualized Table</Caption>\n <Thead>\n <Tr>\n <Th\n select={{\n onSelect: (_event, isSelecting) => selectAllRepos(isSelecting),\n isSelected: areAllReposSelected\n }}\n />\n {columns.map((col, index) => (\n <Th key={++index}>{col}</Th>\n ))}\n </Tr>\n </Thead>\n </Table>\n <AutoSizer disableHeight>\n {({ width }) => (\n <VirtualTableBody\n className=\"pf-v6-c-table pf-v6-c-virtualized pf-v6-c-window-scroller\"\n deferredMeasurementCache={measurementCache}\n rowHeight={measurementCache.rowHeight}\n height={400}\n overscanRowCount={2}\n columnCount={1}\n rows={rows}\n rowCount={rows.length}\n rowRenderer={rowRenderer}\n width={width}\n role=\"grid\"\n />\n )}\n </AutoSizer>\n </div>\n );\n};\n","title":"Selectable","lang":"js","className":""}}> - - </Example>, - 'Actions': props => - <Example {...pageData} {...props} {...{"code":"/* eslint-disable no-console */\nimport React from 'react';\nimport {\n ActionsColumn,\n Caption,\n IActions,\n Table,\n TableGridBreakpoint,\n Td,\n Th,\n Thead,\n Tr\n} from '@patternfly/react-table';\nimport { CellMeasurerCache, CellMeasurer } from 'react-virtualized';\nimport { AutoSizer, VirtualTableBody } from '@patternfly/react-virtualized-extension';\n\nexport const ActionsExample: React.FunctionComponent = () => {\n interface RowType {\n disableActions: boolean;\n id: string;\n cells: string[];\n }\n\n const rows: RowType[] = [];\n for (let i = 0; i < 100; i++) {\n rows.push({\n disableActions: i % 3 === 2,\n id: `actions-row-${i}`,\n cells: [`one-${i}`, `two-${i}`, `three-${i}`, `four-${i}`, `five-${i}`]\n });\n }\n\n const columns = ['Name', 'Namespace', 'Labels', 'Status', 'Pod Selector'];\n\n const actions: IActions = [\n {\n title: 'Some action',\n onClick: (_event, rowId, _rowData, _extra) => console.log('clicked on Some action, on row: ', rowId)\n },\n {\n title: <div>Another action</div>,\n onClick: (_event, rowId, _rowData, _extra) => console.log('clicked on Another action, on row: ', rowId)\n },\n {\n isSeparator: true\n },\n {\n title: 'Third action',\n onClick: (_event, rowId, _rowData, _extra) => console.log('clicked on Third action, on row: ', rowId)\n }\n ];\n\n const measurementCache = new CellMeasurerCache({\n fixedWidth: true,\n minHeight: 44,\n keyMapper: (rowIndex) => rowIndex\n });\n\n const rowRenderer = ({ index: rowIndex, _isScrolling, key, style, parent }) => (\n <CellMeasurer cache={measurementCache} columnIndex={0} key={key} parent={parent} rowIndex={rowIndex}>\n <Tr resetOffset style={style}>\n {columns.map((col, index) => (\n <Td key={`${rowIndex}-${index + 1}`}>{rows[rowIndex].cells[index]}</Td>\n ))}\n <Td isActionCell>\n <ActionsColumn items={actions} isDisabled={rows[rowIndex].disableActions} />\n </Td>\n </Tr>\n </CellMeasurer>\n );\n\n return (\n <div aria-label=\"Scrollable Table\" className=\"pf-v6-c-scrollablegrid\">\n <Table gridBreakPoint={TableGridBreakpoint.none} aria-rowcount={rows.length} variant=\"compact\">\n <Caption>Actions VirtualizedTable</Caption>\n <Thead>\n <Tr>\n <Th key={0}>{columns[0]}</Th>\n <Th key={1}>{columns[1]}</Th>\n <Th key={2}>{columns[2]}</Th>\n <Th key={3}>{columns[3]}</Th>\n <Th key={4}>{columns[4]}</Th>\n <Td isActionCell></Td>\n </Tr>\n </Thead>\n </Table>\n <AutoSizer disableHeight>\n {({ width }) => (\n <VirtualTableBody\n className=\"pf-v6-c-table pf-v6-c-virtualized pf-v6-c-window-scroller\"\n deferredMeasurementCache={measurementCache}\n rowHeight={measurementCache.rowHeight}\n height={400}\n overscanRowCount={2}\n columnCount={1}\n rows={rows}\n rowCount={rows.length}\n rowRenderer={rowRenderer}\n width={width}\n />\n )}\n </AutoSizer>\n </div>\n );\n};\n","title":"Actions","lang":"js","className":""}}> - - </Example>, - 'Filterable with WindowScroller': props => - <Example {...pageData} {...props} {...{"code":"import React from 'react';\nimport { CellMeasurerCache, CellMeasurer } from 'react-virtualized';\nimport { AutoSizer, VirtualTableBody, WindowScroller } from '@patternfly/react-virtualized-extension';\nimport { Table, Thead, Tr, Th, Td, TableGridBreakpoint, ActionsColumn, Tbody } from '@patternfly/react-table';\nimport {\n SelectOption,\n ToolbarItem,\n Select,\n MenuToggleElement,\n MenuToggle,\n ToolbarFilter,\n SearchInput,\n Badge,\n Toolbar,\n ToolbarContent,\n ToolbarToggleGroup,\n ToolbarGroup,\n ToolbarLabelGroup,\n Button,\n EmptyState,\n EmptyStateActions,\n EmptyStateBody,\n EmptyStateFooter,\n EmptyStateVariant,\n Bullseye\n} from '@patternfly/react-core';\nimport { FilterIcon, SearchIcon } from '@patternfly/react-icons';\n\nexport const ComposableTableWindowScroller = () => {\n const [scrollableElement, setScrollableElement] = React.useState<HTMLElement>();\n React.useEffect(() => {\n const scrollableElement = document.getElementById('content-scrollable-2') as HTMLElement;\n setScrollableElement(scrollableElement);\n }, []);\n\n interface DataType {\n cells: (string | number)[];\n id: string;\n disableActions: boolean;\n }\n\n const rows: DataType[] = [];\n for (let i = 0; i < 100; i++) {\n if (i % 2 === 0) {\n rows.push({\n disableActions: false,\n id: `actions-row-${i}`,\n cells: [`US-Node ${i}`, i, i, 'Down', 'Brno']\n });\n } else if (i % 3 === 0) {\n rows.push({\n disableActions: false,\n id: `actions-row-${i}`,\n cells: [`CN-Node ${i}`, i, i, 'Running', 'Westford']\n });\n } else {\n rows.push({\n disableActions: true,\n id: `actions-row-${i}`,\n cells: [`US-Node ${i}`, i, i, 'Stopped', 'Raleigh']\n });\n }\n }\n\n const actions = [\n {\n title: 'Some action',\n // eslint-disable-next-line no-console\n onClick: (_event, rowId, _rowData, _extra) => console.log('clicked on Some action, on row: ', rowId)\n },\n {\n title: <div>Another action</div>,\n // eslint-disable-next-line no-console\n onClick: (_event, rowId, _rowData, _extra) => console.log('clicked on Another action, on row: ', rowId)\n },\n {\n isSeparator: true\n },\n {\n title: 'Third action',\n // eslint-disable-next-line no-console\n onClick: (_event, rowId, _rowData, _extra) => console.log('clicked on Third action, on row: ', rowId)\n }\n ];\n\n const columns = ['Servers', 'Threads', 'Applications', 'Status', 'Location'];\n const scrollToIndex = -1; // can be used to programmatically set current index\n\n const [isCategoryDropdownOpen, setIsCategoryDropdownOpen] = React.useState(false);\n const [isFilterDropdownOpen, setIsFilterDropdownOpen] = React.useState(false);\n const [currentCategory, setCurrentCategory] = React.useState('Name');\n const [filters, setFilters] = React.useState<Record<string, string[]>>({ location: [], name: [], status: [] });\n const [inputValue, setInputValue] = React.useState('');\n\n const onDelete = (type: string | ToolbarLabelGroup, id: string) => {\n if (type === 'Location') {\n setFilters({\n ...filters,\n location: filters.location.filter((fil: string) => fil !== id)\n });\n } else if (type === 'Name') {\n setFilters({\n ...filters,\n name: filters.name.filter((fil: string) => fil !== id)\n });\n } else if (type === 'Status') {\n setFilters({\n ...filters,\n status: filters.status.filter((fil: string) => fil !== id)\n });\n } else {\n setFilters({ location: [], name: [], status: [] });\n }\n };\n\n const onCategoryToggle = () => {\n setIsCategoryDropdownOpen(!isCategoryDropdownOpen);\n };\n\n const onCategorySelect = (event) => {\n setCurrentCategory(event.target.innerText);\n setIsCategoryDropdownOpen(!isCategoryDropdownOpen);\n };\n\n const onFilterToggle = () => {\n setIsFilterDropdownOpen(!isFilterDropdownOpen);\n };\n\n const onInputChange = (newValue: string) => {\n setInputValue(newValue);\n };\n\n const onStatusSelect = (event: React.MouseEvent<Element, MouseEvent> | undefined, selection: string | number | undefined) => {\n const checked = (event?.target as HTMLInputElement).checked;\n setFilters({\n ...filters,\n status: (checked && selection) ? [...filters.status, `${selection}`] : filters.status.filter((value) => value !== selection)\n });\n setIsFilterDropdownOpen(false);\n };\n\n const onNameInput = (event: React.SyntheticEvent<HTMLButtonElement> | React.KeyboardEvent) => {\n setIsCategoryDropdownOpen(false);\n const pressedKey = (event as React.KeyboardEvent).key;\n if (pressedKey && pressedKey !== 'Enter') {\n return;\n }\n\n const prevFilters = filters.name;\n setFilters({ ...filters, name: prevFilters.includes(inputValue) ? prevFilters : [...prevFilters, inputValue] });\n };\n\n const onFilterSelect = () => {\n setIsFilterDropdownOpen(!isFilterDropdownOpen);\n setIsCategoryDropdownOpen(false);\n };\n\n const onLocationSelect = (_event: React.MouseEvent<Element, MouseEvent> | undefined, selection: string | number | undefined) => {\n setFilters({ ...filters, location: [`${selection}`] });\n\n setIsFilterDropdownOpen(false);\n onFilterSelect();\n };\n\n const buildCategoryDropdown = () => {\n const categoryMenuItems = [\n <SelectOption key=\"cat1\" value=\"Location\">\n Location\n </SelectOption>,\n <SelectOption key=\"cat2\" value=\"Name\">\n Name\n </SelectOption>,\n <SelectOption key=\"cat3\" value=\"Status\">\n Status\n </SelectOption>\n ];\n\n return (\n <ToolbarItem>\n <Select\n onSelect={onCategorySelect}\n selected={currentCategory}\n toggle={(toggleRef: React.Ref<MenuToggleElement>) => (\n <MenuToggle\n ref={toggleRef}\n onClick={onCategoryToggle}\n isExpanded={isCategoryDropdownOpen}\n icon={<FilterIcon />}\n style={\n {\n width: '100%',\n verticalAlign: 'text-bottom'\n } as React.CSSProperties\n }\n >\n {currentCategory}\n </MenuToggle>\n )}\n isOpen={isCategoryDropdownOpen}\n >\n {categoryMenuItems}\n </Select>\n </ToolbarItem>\n );\n };\n\n const buildFilterDropdown = () => {\n const locationMenuItems = [\n <SelectOption key=\"raleigh\" value=\"Raleigh\">\n Raleigh\n </SelectOption>,\n <SelectOption key=\"westford\" value=\"Westford\">\n Westford\n </SelectOption>,\n <SelectOption key=\"boston\" value=\"Boston\">\n Boston\n </SelectOption>,\n <SelectOption key=\"brno\" value=\"Brno\">\n Brno\n </SelectOption>,\n <SelectOption key=\"bEmptyStateHeadangalore\" value=\"Bangalore\">\n Bangalore\n </SelectOption>\n ];\n\n const statusMenuItems = [\n <SelectOption hasCheckbox key=\"statusRunning\" value=\"Running\" isSelected={filters.status.includes('Running')}>\n Running\n </SelectOption>,\n <SelectOption hasCheckbox key=\"statusStopped\" value=\"Stopped\" isSelected={filters.status.includes('Stopped')}>\n Stopped\n </SelectOption>,\n <SelectOption hasCheckbox key=\"statusDown\" value=\"Down\" isSelected={filters.status.includes('Down')}>\n Down\n </SelectOption>,\n <SelectOption hasCheckbox key=\"statusDegraded\" value=\"Degraded\" isSelected={filters.status.includes('Degraded')}>\n Degraded\n </SelectOption>,\n <SelectOption\n hasCheckbox\n key=\"statusMaint\"\n value=\"Needs maintenance\"\n isSelected={filters.status.includes('Needs maintenance')}\n >\n Needs maintenance\n </SelectOption>\n ];\n\n return (\n <React.Fragment>\n <ToolbarFilter\n labels={filters.location}\n deleteLabel={(category, chip) => onDelete(category, chip as string)}\n categoryName=\"Location\"\n showToolbarItem={currentCategory === 'Location'}\n >\n <Select\n aria-label=\"Location\"\n onSelect={onLocationSelect}\n selected={filters.location[0]}\n isOpen={isFilterDropdownOpen}\n popperProps={{ minWidth: '100px' }}\n toggle={(toggleRef: React.Ref<MenuToggleElement>) => (\n <MenuToggle\n ref={toggleRef}\n onClick={onFilterToggle}\n isExpanded={isFilterDropdownOpen}\n style={\n {\n width: '100%',\n verticalAlign: 'text-bottom'\n } as React.CSSProperties\n }\n >\n {filters.location[0] || `Any`}\n </MenuToggle>\n )}\n >\n {locationMenuItems}\n </Select>\n </ToolbarFilter>\n <ToolbarFilter\n labels={filters.name}\n deleteLabel={(category, chip) => onDelete(category, chip as string)}\n categoryName=\"Name\"\n showToolbarItem={currentCategory === 'Name'}\n >\n <SearchInput\n aria-label=\"name filter\"\n placeholder=\"Filter by name...\"\n onChange={(_event, value) => onInputChange(value)}\n value={inputValue}\n onClear={() => {\n onInputChange('');\n }}\n onSearch={onNameInput} // any typing is needed because of what I think is a bug in the SearchInput typing\n />\n </ToolbarFilter>\n <ToolbarFilter\n labels={filters.status}\n deleteLabel={(category, chip) => onDelete(category, chip as string)}\n categoryName=\"Status\"\n showToolbarItem={currentCategory === 'Status'}\n >\n <Select\n aria-label=\"Status\"\n isOpen={isFilterDropdownOpen}\n popperProps={{ minWidth: '100px' }}\n onSelect={onStatusSelect}\n selected={filters.status}\n toggle={(toggleRef: React.Ref<MenuToggleElement>) => (\n <MenuToggle\n ref={toggleRef}\n onClick={onFilterToggle}\n isExpanded={isFilterDropdownOpen}\n style={\n {\n width: '100%',\n verticalAlign: 'text-bottom'\n } as React.CSSProperties\n }\n >\n Filter by status\n {filters.status.length > 0 && <Badge isRead>{filters.status.length}</Badge>}\n </MenuToggle>\n )}\n >\n {statusMenuItems}\n </Select>\n </ToolbarFilter>\n </React.Fragment>\n );\n };\n\n const renderToolbar = () => (\n <Toolbar\n id=\"toolbar-with-chip-groups\"\n clearAllFilters={() => setFilters({ location: [], name: [], status: [] })}\n collapseListedFiltersBreakpoint=\"xl\"\n >\n <ToolbarContent>\n <ToolbarToggleGroup toggleIcon={<FilterIcon />} breakpoint=\"xl\">\n <ToolbarGroup variant=\"filter-group\">\n {buildCategoryDropdown()}\n {buildFilterDropdown()}\n </ToolbarGroup>\n </ToolbarToggleGroup>\n </ToolbarContent>\n </Toolbar>\n );\n\n const measurementCache = new CellMeasurerCache({\n fixedWidth: true,\n minHeight: 44,\n keyMapper: (rowIndex) => rowIndex\n });\n\n const filteredRows =\n filters.name.length > 0 || filters.location.length > 0 || filters.status.length > 0\n ? rows.filter(\n (row) =>\n (filters.name.length === 0 ||\n filters.name.some((name) => (row.cells[0] as string).toLowerCase().includes(name.toLowerCase()))) &&\n (filters.location.length === 0 || filters.location.includes(row.cells[4] as string)) &&\n (filters.status.length === 0 || filters.status.includes(row.cells[3] as string))\n )\n : rows;\n\n const emptyState = (\n <EmptyState variant={EmptyStateVariant.xs}\n titleText=\"Clear all filters and try again.\"\n headingLevel=\"h5\"\n icon={SearchIcon}>\n <EmptyStateBody>No results match the filter criteria. Clear all filters and try again.</EmptyStateBody>\n <EmptyStateFooter>\n <EmptyStateActions>\n <Button\n variant=\"link\"\n onClick={() => {\n setFilters({ location: [], name: [], status: [] });\n }}\n >\n Clear all filters\n </Button>\n </EmptyStateActions>\n </EmptyStateFooter>\n </EmptyState>\n );\n\n const rowRenderer = ({ index: rowIndex, _isScrolling, key, style, parent }) => (\n <CellMeasurer cache={measurementCache} columnIndex={0} key={key} parent={parent} rowIndex={rowIndex}>\n <Tr style={style}>\n {columns.map((col, index) => (\n <Td key={`${rowIndex}-${index}`}>{filteredRows[rowIndex].cells[index]}</Td>\n ))}\n <Td isActionCell>\n <ActionsColumn\n items={actions}\n isDisabled={filteredRows[rowIndex].disableActions} // Also arbitrary for the example\n />\n </Td>\n </Tr>\n </CellMeasurer>\n );\n\n interface ScrollableContainerStyle {\n height: number;\n overflowX: 'auto';\n overflowY: 'scroll';\n scrollBehavior: 'smooth';\n WebkitOverflowScrolling: 'touch';\n position: 'relative';\n }\n\n const scrollableContainerStyle: ScrollableContainerStyle = {\n height: 500 /* important note: the scrollable container should have some sort of fixed height, or it should be wrapped in container that is smaller than ReactVirtualized__VirtualGrid container and has overflow visible if using the Window Scroller. See WindowScroller.example.css */,\n overflowX: 'auto',\n overflowY: 'scroll',\n scrollBehavior: 'smooth',\n WebkitOverflowScrolling: 'touch',\n position: 'relative'\n };\n\n return (\n <div\n id=\"content-scrollable-2\"\n aria-label=\"Scrollable Table\"\n className=\"pf-v6-c-scrollablegrid\"\n style={scrollableContainerStyle}\n >\n {renderToolbar()}\n <Table gridBreakPoint={TableGridBreakpoint.none} aria-rowcount={rows.length}>\n <Thead>\n <Tr>\n {columns.map((col, index) => (\n <Th key={index}>{col}</Th>\n ))}\n <Td isActionCell></Td>\n </Tr>\n </Thead>\n {filteredRows.length === 0 && (\n <Tbody>\n <Tr>\n <Td colSpan={8}>\n <Bullseye>{emptyState}</Bullseye>\n </Td>\n </Tr>\n </Tbody>\n )}\n </Table>\n <WindowScroller scrollElement={scrollableElement}>\n {({ height, isScrolling, registerChild, onChildScroll, scrollTop }) => (\n <AutoSizer disableHeight>\n {({ width }) => (\n <div ref={registerChild as (element: HTMLDivElement | null) => void}>\n <VirtualTableBody\n autoHeight\n className={'pf-v6-c-table pf-v6-c-virtualized pf-v6-c-window-scroller'}\n deferredMeasurementCache={measurementCache}\n rowHeight={measurementCache.rowHeight}\n height={height || 0}\n isScrolling={isScrolling}\n isScrollingOptOut={true}\n onScroll={onChildScroll}\n overscanRowCount={2}\n columnCount={1}\n rows={filteredRows}\n rowCount={filteredRows.length}\n rowRenderer={rowRenderer}\n scrollToIndex={scrollToIndex}\n scrollTop={scrollTop}\n width={width}\n role=\"grid\"\n />\n </div>\n )}\n </AutoSizer>\n )}\n </WindowScroller>\n </div>\n );\n};\n","title":"Filterable with WindowScroller","lang":"js","className":""}}> - - </Example> -}; - -const Component = () => ( - <Fragment> - <p {...{"className":"pf-v6-c-content--p pf-m-editorial ws-p "}}> - {`Note: React Virtualized Extension lives in its own package at `} - <PatternflyThemeLink {...{"to":"https://www.npmjs.com/package/@patternfly/react-virtualized-extension","className":""}}> - <code {...{"className":"ws-code "}}> - {`@patternfly/react-virtualized-extension`} - </code> - </PatternflyThemeLink> - {`!`} - </p> - <AutoLinkHeader {...{"id":"examples","headingLevel":"h2","className":"ws-title ws-h2"}}> - {`Examples`} - </AutoLinkHeader> - {createElement(pageData.examples["Basic"])} - {createElement(pageData.examples["Sortable"])} - {createElement(pageData.examples["Selectable"])} - {createElement(pageData.examples["Actions"])} - {createElement(pageData.examples["Filterable with WindowScroller"])} - </Fragment> -); -Component.displayName = 'ExtensionsVirtualScrollTableReactDocs'; -Component.pageData = pageData; - -export default Component; diff --git a/packages/module/patternfly-docs/generated/extensions/virtual-scroll-window-scroller/react.js b/packages/module/patternfly-docs/generated/extensions/virtual-scroll-window-scroller/react.js deleted file mode 100644 index 25ff0ce..0000000 --- a/packages/module/patternfly-docs/generated/extensions/virtual-scroll-window-scroller/react.js +++ /dev/null @@ -1,216 +0,0 @@ -import { createElement, Fragment } from 'react'; -import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; -import { CellMeasurerCache, CellMeasurer } from 'react-virtualized'; -import { AutoSizer, VirtualTableBody, WindowScroller } from '@patternfly/react-virtualized-extension'; -import { Table as TableDeprecated, TableHeader as TableHeaderDeprecated } from '@patternfly/react-table/deprecated'; -import '../../../content/examples/./VirtualGrid.example.css'; -import '../../../content/examples/./WindowScroller.example.css'; -const pageData = { - "id": "Virtual scroll window scroller", - "section": "extensions", - "subsection": "", - "deprecated": false, - "template": false, - "beta": false, - "demo": false, - "newImplementationLink": false, - "source": "react", - "tabName": null, - "slug": "/extensions/virtual-scroll-window-scroller/react", - "sourceLink": "https://github.com/patternfly/react-virtualized-extension", - "relPath": "packages/module/patternfly-docs/content/examples/WindowScroller.md", - "propComponents": [ - { - "name": "VirtualTableBody", - "description": "It is inefficient to create and manage a large list of DOM elements within a scrolling container\nif only a few of those elements are visible. The primary purpose of this component is to improve\nperformance by only rendering the DOM nodes that a user is able to see based on their current\nscroll position.\n\nThis component renders a virtualized list of elements with either fixed or dynamic heights.", - "props": [ - { - "name": "aria-label", - "type": "string", - "description": "" - }, - { - "name": "autoHeight", - "type": "boolean", - "description": "Removes fixed height from the scrollingContainer so that the total height\nof rows can stretch the window. Intended for use with WindowScroller", - "defaultValue": "false" - }, - { - "name": "className", - "type": "string", - "description": "Optional CSS class name" - }, - { - "name": "columnCount", - "type": "number", - "description": "" - }, - { - "name": "columns", - "type": "any[]", - "description": "" - }, - { - "name": "estimatedRowSize", - "type": "number", - "description": "Used to estimate the total height of a List before all of its rows have actually been measured.\nThe estimated total height is adjusted as rows are rendered.", - "defaultValue": "30" - }, - { - "name": "height", - "type": "number", - "description": "Height constraint for list (determines how many actual rows are rendered)", - "required": true - }, - { - "name": "innerScrollContainerComponent", - "type": "No type info", - "defaultValue": "'tbody'" - }, - { - "name": "noRowsRenderer", - "type": "NoContentRenderer", - "description": "Optional renderer to be used in place of rows when rowCount is 0", - "defaultValue": "() => null as any" - }, - { - "name": "onRowsRendered", - "type": "(params: any) => void", - "description": "Callback invoked with information about the slice of rows that were just rendered.", - "defaultValue": "() => {}" - }, - { - "name": "onScroll", - "type": "(params: Scroll) => void", - "description": "Callback invoked whenever the scroll offset changes within the inner scrollable region.\nThis callback can be used to sync scrolling between lists, tables, or grids.", - "defaultValue": "() => {}" - }, - { - "name": "overscanIndicesGetter", - "type": "OverscanIndicesGetter", - "description": "See VirtualGrid#overscanIndicesGetter", - "defaultValue": "accessibilityOverscanIndicesGetter" - }, - { - "name": "overscanRowCount", - "type": "number", - "description": "Number of rows to render above/below the visible bounds of the list.\nThese rows can help for smoother scrolling on touch devices.", - "defaultValue": "10" - }, - { - "name": "rowCount", - "type": "number", - "description": "Number of rows in list.", - "required": true - }, - { - "name": "rowHeight", - "type": "CellSize", - "description": "Either a fixed row height (number) or a function that returns the height of a row given its index.", - "required": true - }, - { - "name": "rowRenderer", - "type": "any", - "description": "Responsible for rendering a row given an index; ({ index: number }): node", - "required": true - }, - { - "name": "rows", - "type": "any[]", - "description": "", - "required": true - }, - { - "name": "scrollContainerComponent", - "type": "No type info", - "defaultValue": "'table'" - }, - { - "name": "scrollToAlignment", - "type": "Alignment", - "description": "See VirtualGrid#scrollToAlignment", - "defaultValue": "'auto'" - }, - { - "name": "scrollToIndex", - "type": "number", - "description": "Row index to ensure visible (by forcefully scrolling if necessary)", - "defaultValue": "-1" - }, - { - "name": "scrollTop", - "type": "number", - "description": "Vertical offset." - }, - { - "name": "style", - "type": "Object", - "description": "", - "defaultValue": "{}" - }, - { - "name": "tabIndex", - "type": "number", - "description": "Tab index for focus" - }, - { - "name": "width", - "type": "number", - "description": "Width of list", - "required": true - } - ] - } - ], - "examples": [ - "Window scroller" - ] -}; -pageData.liveContext = { - CellMeasurerCache, - CellMeasurer, - AutoSizer, - VirtualTableBody, - WindowScroller, - TableDeprecated, - TableHeaderDeprecated -}; -pageData.relativeImports = "import 'content/examples/./VirtualGrid.example.css';,import 'content/examples/./WindowScroller.example.css';" -pageData.examples = { - 'Window scroller': props => - <Example {...pageData} {...props} {...{"code":"import React from 'react';\nimport { CellMeasurerCache, CellMeasurer } from 'react-virtualized';\nimport { AutoSizer, VirtualTableBody, WindowScroller } from '@patternfly/react-virtualized-extension';\nimport { Table, Thead, Tr, Th, Td, Caption, TableGridBreakpoint } from '@patternfly/react-table';\n\nexport const WindowScrollerExample = () => {\n const [scrollableElement, setScrollableElement] = React.useState<HTMLElement>();\n React.useEffect(() => {\n const scrollableElement = document.getElementById('content-scrollable-2') as HTMLElement;\n setScrollableElement(scrollableElement);\n }, []);\n\n // this StringArray type is just needed because something in our documentation framework crashes when it encounters\n // a string[][] type\n type StringArray = string[];\n const rows: StringArray[] = [];\n\n for (let i = 0; i < 100000; i++) {\n const cells: string[] = [];\n const num = Math.floor(Math.random() * Math.floor(2)) + 1;\n for (let j = 0; j < 5; j++) {\n const cellValue = i.toString() + ' Arma virumque cano Troiae qui primus ab oris. '.repeat(num);\n cells.push(cellValue);\n }\n rows.push(cells);\n }\n\n const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last Commit'];\n const scrollToIndex = -1; // can be used to programmatically set current index\n\n const measurementCache = new CellMeasurerCache({\n fixedWidth: true,\n minHeight: 44,\n keyMapper: (rowIndex) => rowIndex\n });\n\n const rowRenderer = ({ index: rowIndex, _isScrolling, key, style, parent }) => {\n const text = rows[rowIndex][0];\n\n return (\n <CellMeasurer cache={measurementCache} columnIndex={0} key={key} parent={parent} rowIndex={rowIndex}>\n <Tr style={style}>\n {columns.map((col, index) => (\n <Td key={`${rowIndex}-${++index}`}>{text}</Td>\n ))}\n </Tr>\n </CellMeasurer>\n );\n };\n\n interface ScrollableContainerStyle {\n height: number;\n overflowX: 'auto';\n overflowY: 'scroll';\n scrollBehavior: 'smooth';\n WebkitOverflowScrolling: 'touch';\n position: 'relative';\n }\n\n const scrollableContainerStyle: ScrollableContainerStyle = {\n height: 500 /* important note: the scrollable container should have some sort of fixed height, or it should be wrapped in container that is smaller than ReactVirtualized__VirtualGrid container and has overflow visible if using the Window Scroller. See WindowScroller.example.css */,\n overflowX: 'auto',\n overflowY: 'scroll',\n scrollBehavior: 'smooth',\n WebkitOverflowScrolling: 'touch',\n position: 'relative'\n };\n\n return (\n <div\n id=\"content-scrollable-2\"\n aria-label=\"Scrollable Table\"\n className=\"pf-v6-c-scrollablegrid\"\n style={scrollableContainerStyle}\n >\n <Table gridBreakPoint={TableGridBreakpoint.none} aria-rowcount={rows.length}>\n <Caption>\n WindowScroller allows scrolling of a parent container or the window instead of tbody. It also can be used to\n dynamically size the table to the size of the scroll element.\n </Caption>\n <Thead>\n <Tr>\n {columns.map((col, index) => (\n <Th key={++index}>{col}</Th>\n ))}\n </Tr>\n </Thead>\n </Table>\n <WindowScroller scrollElement={scrollableElement}>\n {({ height, isScrolling, registerChild, onChildScroll, scrollTop }) => (\n <AutoSizer disableHeight>\n {({ width }) => (\n <div ref={registerChild as (element: HTMLDivElement | null) => void}>\n <VirtualTableBody\n autoHeight\n className={'pf-v6-c-table pf-v6-c-virtualized pf-v6-c-window-scroller'}\n deferredMeasurementCache={measurementCache}\n rowHeight={measurementCache.rowHeight}\n height={height || 0}\n isScrolling={isScrolling}\n isScrollingOptOut={true}\n onScroll={onChildScroll}\n overscanRowCount={2}\n columnCount={1}\n rows={rows}\n rowCount={rows.length}\n rowRenderer={rowRenderer}\n scrollToIndex={scrollToIndex}\n scrollTop={scrollTop}\n width={width}\n role=\"grid\"\n />\n </div>\n )}\n </AutoSizer>\n )}\n </WindowScroller>\n </div>\n );\n};\n","title":"Window scroller","lang":"js","className":""}}> - - </Example> -}; - -const Component = () => ( - <Fragment> - <p {...{"className":"pf-v6-c-content--p pf-m-editorial ws-p "}}> - {`Note: React Virtualized Extension lives in its own package at `} - <PatternflyThemeLink {...{"to":"https://www.npmjs.com/package/@patternfly/react-virtualized-extension","className":""}}> - <code {...{"className":"ws-code "}}> - {`@patternfly/react-virtualized-extension`} - </code> - </PatternflyThemeLink> - {`! -`} - <br/> - {` -This package is currently an extension. Extension components do not undergo the same rigorous design or coding review process as core PatternFly components. If enough members of the community find them useful, we will work to move them into our core PatternFly system by starting the design process for the idea. -`} - <br/> - {` -`} - <br/> - </p> - <AutoLinkHeader {...{"id":"examples","headingLevel":"h2","className":"ws-title ws-h2"}}> - {`Examples`} - </AutoLinkHeader> - {createElement(pageData.examples["Window scroller"])} - </Fragment> -); -Component.displayName = 'ExtensionsVirtualScrollWindowScrollerReactDocs'; -Component.pageData = pageData; - -export default Component; diff --git a/packages/module/patternfly-docs/generated/index.js b/packages/module/patternfly-docs/generated/index.js deleted file mode 100644 index 5b00105..0000000 --- a/packages/module/patternfly-docs/generated/index.js +++ /dev/null @@ -1,24 +0,0 @@ -module.exports = { - '/extensions/virtual-scroll-window-scroller/react': { - id: "Virtual scroll window scroller", - title: "Virtual scroll window scroller", - toc: [{"text":"Examples"},[{"text":"Window scroller"}]], - examples: ["Window scroller"], - section: "extensions", - subsection: "", - source: "react", - tabName: null, - Component: () => import(/* webpackChunkName: "extensions/virtual-scroll-window-scroller/react/index" */ './extensions/virtual-scroll-window-scroller/react') - }, - '/extensions/virtual-scroll-table/react': { - id: "Virtual scroll table", - title: "Virtual scroll table", - toc: [{"text":"Examples"},[{"text":"Basic"},{"text":"Sortable"},{"text":"Selectable"},{"text":"Actions"},{"text":"Filterable with WindowScroller"}]], - examples: ["Basic","Sortable","Selectable","Actions","Filterable with WindowScroller"], - section: "extensions", - subsection: "", - source: "react", - tabName: null, - Component: () => import(/* webpackChunkName: "extensions/virtual-scroll-table/react/index" */ './extensions/virtual-scroll-table/react') - } -}; \ No newline at end of file diff --git a/packages/module/patternfly-docs/generated/react.js b/packages/module/patternfly-docs/generated/react.js deleted file mode 100644 index 4e9271e..0000000 --- a/packages/module/patternfly-docs/generated/react.js +++ /dev/null @@ -1,59 +0,0 @@ -import { createElement, Fragment } from 'react'; -import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; -import { ExtendedButton } from "@patternfly/react-virtualized-extension"; -const pageData = { - "id": "React virtualized extension", - "section": "extensions", - "source": "react", - "slug": "/extensions/react-virtualized-extension/react", - "sourceLink": "https://github.com/patternfly/patternfly-react/blob/main/packages/module/patternfly-docs/content/extensions/react-virtualized-extension/examples/basic.md", - "propComponents": [ - { - "name": "ExtendedButton", - "description": "", - "props": [ - { - "name": "children", - "type": "React.ReactNode", - "description": "Content to render inside the extended button component" - } - ] - } - ], - "examples": [ - "Example" - ], - "fullscreenExamples": [ - "Fullscreen example" - ] -}; -pageData.liveContext = { - ExtendedButton -}; -pageData.relativeImports = { - -}; -pageData.examples = { - 'Example': props => - <Example {...pageData} {...props} {...{"code":"import React from 'react';\nimport { ExtendedButton } from '@patternfly/react-virtualized-extension';\n\nexport const BasicExample: React.FunctionComponent = () => <ExtendedButton>My custom extension button</ExtendedButton>;\n","title":"Example","lang":"js"}}> - - </Example>, - 'Fullscreen example': props => - <Example {...pageData} {...props} {...{"code":"import React from 'react';\nimport { ExtendedButton } from '@patternfly/react-virtualized-extension';\n\nexport const BasicExample: React.FunctionComponent = () => <ExtendedButton>My custom extension button</ExtendedButton>;\n","title":"Fullscreen example","lang":"js","isFullscreen":true}}> - - </Example> -}; - -const Component = () => ( - <Fragment> - <AutoLinkHeader {...{"id":"basic-usage","size":"h2","className":"ws-title ws-h2"}}> - {`Basic usage`} - </AutoLinkHeader> - {createElement(pageData.examples["Example"])} - {createElement(pageData.examples["Fullscreen example"])} - </Fragment> -); -Component.displayName = 'ExtensionsPatternflyExtensionSeedReactDocs'; -Component.pageData = pageData; - -export default Component; diff --git a/packages/module/src/components/Virtualized/testDataSets.tsx b/packages/module/src/components/Virtualized/testDataSets.tsx index 2a3d4be..3094a07 100644 --- a/packages/module/src/components/Virtualized/testDataSets.tsx +++ b/packages/module/src/components/Virtualized/testDataSets.tsx @@ -2,7 +2,7 @@ // This file is test data pulled from the @patternfly/react-table package -import type { MouseEvent } from 'react'; +import type { MouseEvent as ReactMouseEvent } from 'react'; import { IRow, ICell, IActions, EditableTextCell } from '@patternfly/react-table'; export const columns: (ICell | string)[] = [ @@ -198,13 +198,13 @@ export const editableRows: IRow[] = [ export const actions: IActions = [ { title: 'Some action', - onClick: (event: MouseEvent, rowId: number) => + onClick: (event: ReactMouseEvent, rowId: number) => // tslint:disable-next-line:no-console console.log('clicked on Some action, on row: ', rowId) }, { title: <div>Another action</div>, - onClick: (event: MouseEvent, rowId: number) => + onClick: (event: ReactMouseEvent, rowId: number) => // tslint:disable-next-line:no-console console.log('clicked on Another action, on row: ', rowId) }, @@ -214,7 +214,7 @@ export const actions: IActions = [ }, { title: 'Third action', - onClick: (event: MouseEvent, rowId: number) => + onClick: (event: ReactMouseEvent, rowId: number) => // tslint:disable-next-line:no-console console.log('clicked on Third action, on row: ', rowId) } diff --git a/yarn.lock b/yarn.lock index ff4954a..5f937ed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10257,12 +10257,12 @@ react-docgen@5.3.1: strip-indent "^3.0.0" "react-dom@^17.0.0 || ^18.0.0": - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" - integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" + integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== dependencies: loose-envify "^1.1.0" - scheduler "^0.23.0" + scheduler "^0.23.2" react-dropzone@14.2.3, react-dropzone@^14.2.3: version "14.2.3" @@ -10318,9 +10318,9 @@ react-virtualized@^9.22.5: react-lifecycles-compat "^3.0.4" "react@^17.0.0 || ^18.0.0": - version "18.2.0" - resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" - integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== + version "18.3.1" + resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" + integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== dependencies: loose-envify "^1.1.0" @@ -10821,10 +10821,10 @@ saxes@^6.0.0: dependencies: xmlchars "^2.2.0" -scheduler@^0.23.0: - version "0.23.0" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" - integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== +scheduler@^0.23.2: + version "0.23.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" + integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== dependencies: loose-envify "^1.1.0"