Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions packages/react-core/src/components/Compass/Compass.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Drawer, DrawerContent, DrawerContentBody, DrawerProps } from '../Drawer';
import styles from '@patternfly/react-styles/css/components/Compass/compass';
import { css } from '@patternfly/react-styles';
import { IS_INERT } from '../../helpers/inert';

import compassBackgroundImageLight from '@patternfly/react-tokens/dist/esm/c_compass_BackgroundImage_light';
import compassBackgroundImageDark from '@patternfly/react-tokens/dist/esm/c_compass_BackgroundImage_dark';
Expand Down Expand Up @@ -76,15 +77,15 @@ export const Compass: React.FunctionComponent<CompassProps> = ({
{header && (
<div
className={css(styles.compassHeader, isHeaderExpanded && 'pf-m-expanded')}
{...(!isHeaderExpanded && { inert: 'true' })}
{...(!isHeaderExpanded && { inert: IS_INERT })}
>
{header}
</div>
)}
{sidebarStart && (
<div
className={css(styles.compassSidebar, styles.modifiers.start, isSidebarStartExpanded && 'pf-m-expanded')}
{...(!isSidebarStartExpanded && { inert: 'true' })}
{...(!isSidebarStartExpanded && { inert: IS_INERT })}
>
{sidebarStart}
</div>
Expand All @@ -93,15 +94,15 @@ export const Compass: React.FunctionComponent<CompassProps> = ({
{sidebarEnd && (
<div
className={css(styles.compassSidebar, styles.modifiers.end, isSidebarEndExpanded && 'pf-m-expanded')}
{...(!isSidebarEndExpanded && { inert: 'true' })}
{...(!isSidebarEndExpanded && { inert: IS_INERT })}
>
{sidebarEnd}
</div>
)}
{footer && (
<div
className={css(styles.compassFooter, isFooterExpanded && 'pf-m-expanded')}
{...(!isFooterExpanded && { inert: 'true' })}
{...(!isFooterExpanded && { inert: IS_INERT })}
>
{footer}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { FocusTrap } from '../../helpers/FocusTrap/FocusTrap';
import cssPanelMdFlexBasis from '@patternfly/react-tokens/dist/esm/c_drawer__panel_md_FlexBasis';
import cssPanelMdFlexBasisMin from '@patternfly/react-tokens/dist/esm/c_drawer__panel_md_FlexBasis_min';
import cssPanelMdFlexBasisMax from '@patternfly/react-tokens/dist/esm/c_drawer__panel_md_FlexBasis_max';
import { IS_INERT } from '../../helpers/inert';

export interface DrawerPanelFocusTrapObject {
/** Enables a focus trap on the drawer panel content. This will also automatically
Expand Down Expand Up @@ -394,7 +395,7 @@ export const DrawerPanelContent: React.FunctionComponent<DrawerPanelContentProps
...((defaultSize || minSize || maxSize) && boundaryCssVars),
...style
}}
{...(shouldCollapseSpace && { inert: '' })}
{...(shouldCollapseSpace && { inert: IS_INERT })}
{...props}
ref={panel}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import RhMicronsCaretDownIcon from '@patternfly/react-icons/dist/esm/icons/rh-mi
import { flattenTree } from './treeUtils';
import { DualListSelectorListContext } from './DualListSelectorContext';
import { useHasAnimations } from '../../helpers';
import { IS_INERT } from '../../helpers/inert';

export interface DualListSelectorTreeItemProps extends React.HTMLProps<HTMLLIElement> {
/** Content rendered inside the dual list selector. */
Expand Down Expand Up @@ -78,7 +79,7 @@ const DualListSelectorTreeItemBase: React.FunctionComponent<DualListSelectorTree
(child) =>
isValidElement(child) &&
cloneElement(child as React.ReactElement<any>, {
inert: isExpanded ? undefined : ''
inert: isExpanded ? undefined : IS_INERT
})
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { css } from '@patternfly/react-styles';
import { FormFieldGroupToggle } from './FormFieldGroupToggle';
import { useSSRSafeId } from '../../helpers';
import { useHasAnimations } from '../../helpers';
import { IS_INERT } from '../../helpers/inert';

export interface InternalFormFieldGroupProps extends Omit<React.HTMLProps<HTMLDivElement>, 'label' | 'onToggle'> {
/** Anything that can be rendered as form field group content. */
Expand Down Expand Up @@ -72,7 +73,7 @@ export const InternalFormFieldGroup: React.FunctionComponent<InternalFormFieldGr
{(!isExpandable || (isExpandable && isExpanded) || (hasAnimations && isExpandable)) && (
<div
className={css(styles.formFieldGroupBody)}
{...(hasAnimations && isExpandable && !isExpanded && { inert: '' })}
{...(hasAnimations && isExpandable && !isExpanded && { inert: IS_INERT })}
>
{children}
</div>
Expand Down
3 changes: 2 additions & 1 deletion packages/react-core/src/components/Nav/NavExpandable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { PageSidebarContext } from '../Page/PageSidebar';
import { PickOptional } from '../../helpers/typeUtils';
import { getOUIAProps, OUIAProps } from '../../helpers';
import { SSRSafeIds } from '../../helpers/SSRSafeIds/SSRSafeIds';
import { IS_INERT } from '../../helpers/inert';

export interface NavExpandableProps
extends Omit<React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>, 'title'>, OUIAProps {
Expand Down Expand Up @@ -149,7 +150,7 @@ class NavExpandable extends Component<NavExpandableProps, NavExpandableState> {
className={css(styles.navSubnav)}
aria-labelledby={navId}
hidden={expandedState ? null : true}
{...(!expandedState && { inert: '' })}
{...(!expandedState && { inert: IS_INERT })}
>
{srText && (
<h2 className="pf-v6-screen-reader" id={navId}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { Popper } from '../../helpers';
import { useHasAnimations } from '../../helpers';
import textInputGroupStyles from '@patternfly/react-styles/css/components/TextInputGroup/text-input-group';
import inputGroupStyles from '@patternfly/react-styles/css/components/InputGroup/input-group';
import { IS_INERT } from '../../helpers/inert';

/** Properties for adding search attributes to an advanced search input. These properties must
* be passed in as an object within an array to the search input component's attribute property.
Expand Down Expand Up @@ -404,14 +405,14 @@ const SearchInputBase: React.FunctionComponent<SearchInputProps> = ({
className={inputGroupStyles.modifiers.searchExpand}
isPlain
onTransitionEnd={onTransitionEnd}
{...(isExpanded && { inert: '' })}
{...(isExpanded && { inert: IS_INERT })}
>
{expandToggleButton}
</InputGroupItem>
<InputGroupItem
className={inputGroupStyles.modifiers.searchAction}
isPlain
{...(!isExpanded && { inert: '' })}
{...(!isExpanded && { inert: IS_INERT })}
>
{collapseToggleButton}
</InputGroupItem>
Expand All @@ -426,7 +427,7 @@ const SearchInputBase: React.FunctionComponent<SearchInputProps> = ({
{...(!hasAnimations && { isFill: true })}
{...(hasAnimations && { className: inputGroupStyles.modifiers.searchInput })}
{...(!isExpanded && {
inert: ''
inert: IS_INERT
})}
>
{buildTextInputGroup()}
Expand All @@ -451,7 +452,7 @@ const SearchInputBase: React.FunctionComponent<SearchInputProps> = ({
{...(expandableInput &&
hasAnimations &&
!isExpanded && {
inert: ''
inert: IS_INERT
})}
>
{buildTextInputGroup()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { TreeViewDataItem } from './TreeView';
import { Badge } from '../Badge';
import { useSSRSafeId } from '../../helpers';
import { useHasAnimations } from '../../helpers';
import { IS_INERT } from '../../helpers/inert';

export interface TreeViewCheckProps extends Omit<Partial<React.InputHTMLAttributes<HTMLInputElement>>, 'checked'> {
checked?: boolean | null;
Expand Down Expand Up @@ -225,7 +226,7 @@ const TreeViewListItemBase: React.FunctionComponent<TreeViewListItemProps> = ({
(child) =>
isValidElement(child) &&
cloneElement(child as React.ReactElement<any>, {
inert: internalIsExpanded ? undefined : ''
inert: internalIsExpanded ? undefined : IS_INERT
})
);

Expand Down
7 changes: 7 additions & 0 deletions packages/react-core/src/helpers/inert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { version } from 'react';

/**
* Before React 19, React JSX treats empty string "" as truthy for inert prop.
* @see {@link https://stackoverflow.com/questions/72720469}
*/
export const IS_INERT = Number(version.split('.')[0]) >= 19 ? true : ('' as unknown as boolean);
Comment on lines +1 to +7
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Is versiona stable named export from thereact package across React 17, 18, and 19, and what format does it follow?

💡 Result:

Yes. version is a stable named export from the react package across React 17, 18, and 19. Format: it follows the same “version string” format React uses for stable vs prerelease npm channels. For the Latest (stable) channel it’s SemVer-style major.minor.patch (e.g. 18.0.0), but for prerelease channel builds (Canary/Experimental) React generates a version string that includes extra metadata (hash + commit date), in the pattern shown by React’s versioning policy docs (e.g. 18.3.0-canary-- / 0.0.0-experimental--).

Citations:


React's version export is stable, but prerelease builds require special handling.

The version export is confirmed as a stable named export across React 17, 18, and 19. For stable releases, it follows SemVer format (major.minor.patch), so version.split('.')[0] reliably extracts the major version. However, prerelease builds (Canary/Experimental) use an extended format like 0.0.0-experimental-<hash>-<YYYYMMDD>, which would cause the version parsing logic to extract 0 instead of the actual major version. Consider adding a safeguard if prerelease versions need to be handled explicitly, or document that this code path uses the conservative fallback for prerelease builds.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react-core/src/helpers/inert.ts` around lines 1 - 7, The current
IS_INERT computation reads React's version string naively and will mis-handle
prerelease tags like "0.0.0-experimental-..."; update the export const IS_INERT
logic to robustly extract the numeric major version from the version string
(e.g. use a regex to find the first contiguous digits /(\d+)/, parseInt that
result, and fall back to 0 when no numeric major is found) and then compute
Number(major) >= 19; change the symbol export const IS_INERT accordingly so
prerelease formats safely fall back to the conservative behavior.

3 changes: 2 additions & 1 deletion packages/react-table/src/components/Table/Tr.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import styles from '@patternfly/react-styles/css/components/Table/table';
import inlineStyles from '@patternfly/react-styles/css/components/InlineEdit/inline-edit';
import { css } from '@patternfly/react-styles';
import { TableContext } from './Table';
import { IS_INERT } from './utils/inert';

export interface TrProps extends Omit<React.HTMLProps<HTMLTableRowElement>, 'onResize'>, OUIAProps {
/** Content rendered inside the <tr> row */
Expand Down Expand Up @@ -115,7 +116,7 @@ const TrBase: React.FunctionComponent<TrProps> = ({
{...(isClickable && { tabIndex: 0 })}
aria-label={ariaLabel}
ref={innerRef}
{...(hasAnimations && rowIsHidden && { inert: '' })}
{...(hasAnimations && rowIsHidden && { inert: IS_INERT })}
{...(onRowClick && { onClick: onRowClick, onKeyDown })}
{...ouiaProps}
{...props}
Expand Down
7 changes: 7 additions & 0 deletions packages/react-table/src/components/Table/utils/inert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { version } from 'react';

/**
* Before React 19, React JSX treats empty string "" as truthy for inert prop.
* @see {@link https://stackoverflow.com/questions/72720469}
*/
export const IS_INERT = Number(version.split('.')[0]) >= 19 ? true : ('' as unknown as boolean);
Loading