Skip to content

Commit 1c3dd97

Browse files
authored
fix: replace react useId with lodash uniqueId (#11351) (#11357)
* fix: replace react useId with lodash uniqueId (#11351) * fix: use `GenerateId` instead of lodash.uniqueId
1 parent 6a1686f commit 1c3dd97

File tree

2 files changed

+124
-120
lines changed

2 files changed

+124
-120
lines changed

packages/react-core/src/components/Card/CardHeader.tsx

Lines changed: 108 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Button } from '../Button';
99
import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon';
1010
import { Radio } from '../Radio';
1111
import { Checkbox } from '../Checkbox';
12+
import { GenerateId } from '../../helpers/GenerateId/GenerateId';
1213

1314
export interface CardHeaderActionsObject {
1415
/** Actions of the card header */
@@ -87,122 +88,122 @@ export const CardHeader: React.FunctionComponent<CardHeaderProps> = ({
8788
toggleButtonProps,
8889
isToggleRightAligned,
8990
...props
90-
}: CardHeaderProps) => {
91-
const uniqueId = React.useId();
92-
93-
return (
94-
<CardContext.Consumer>
95-
{({ cardId, isClickable, isSelectable, isSelected, isDisabled: isCardDisabled }) => {
96-
const cardHeaderToggle = (
97-
<div className={css(styles.cardHeaderToggle)}>
98-
<Button
99-
variant="plain"
100-
type="button"
101-
onClick={(evt) => {
102-
onExpand(evt, cardId);
103-
}}
104-
{...toggleButtonProps}
105-
icon={
106-
<span className={css(styles.cardHeaderToggleIcon)}>
107-
<AngleRightIcon />
108-
</span>
109-
}
110-
/>
111-
</div>
112-
);
113-
114-
const isClickableOrSelectableOnly = (isClickable && !isSelectable) || (isSelectable && !isClickable);
115-
if (actions?.actions && isClickableOrSelectableOnly) {
116-
// eslint-disable-next-line no-console
117-
console.error(
118-
`Card: ${
119-
isClickable ? 'Clickable' : 'Selectable'
120-
} only cards should not contain any other actions. If you wish to include additional actions, use a clickable and selectable card.`
91+
}: CardHeaderProps) => (
92+
<GenerateId>
93+
{(randomId) => (
94+
<CardContext.Consumer>
95+
{({ cardId, isClickable, isSelectable, isSelected, isDisabled: isCardDisabled }) => {
96+
const cardHeaderToggle = (
97+
<div className={css(styles.cardHeaderToggle)}>
98+
<Button
99+
variant="plain"
100+
type="button"
101+
onClick={(evt) => {
102+
onExpand(evt, cardId);
103+
}}
104+
{...toggleButtonProps}
105+
icon={
106+
<span className={css(styles.cardHeaderToggleIcon)}>
107+
<AngleRightIcon />
108+
</span>
109+
}
110+
/>
111+
</div>
121112
);
122-
}
123113

124-
const isClickableOnlyCard = isClickable && !isSelectable;
125-
if (
126-
(isClickableOnlyCard || isSelectable) &&
127-
!selectableActions?.selectableActionAriaLabel &&
128-
!selectableActions?.selectableActionAriaLabelledby
129-
) {
130-
// eslint-disable-next-line no-console
131-
console.error(
132-
`Card: ${isClickableOnlyCard ? 'Clickable-only cards' : 'Cards with a selectable input'} must have either the selectableActions.selectableActionAriaLabel or selectableActions.selectableActionAriaLabelledby prop passed in order to provide an accessible name to the clickable element.`
133-
);
134-
}
114+
const isClickableOrSelectableOnly = (isClickable && !isSelectable) || (isSelectable && !isClickable);
115+
if (actions?.actions && isClickableOrSelectableOnly) {
116+
// eslint-disable-next-line no-console
117+
console.error(
118+
`Card: ${
119+
isClickable ? 'Clickable' : 'Selectable'
120+
} only cards should not contain any other actions. If you wish to include additional actions, use a clickable and selectable card.`
121+
);
122+
}
135123

136-
const SelectableCardInput = selectableActions?.variant === 'single' ? Radio : Checkbox;
137-
const getSelectableProps = () => ({
138-
className: css('pf-m-standalone'),
139-
inputClassName: css(selectableActions?.isHidden && 'pf-v6-screen-reader'),
140-
label: <></>,
141-
'aria-label': selectableActions.selectableActionAriaLabel,
142-
'aria-labelledby': selectableActions.selectableActionAriaLabelledby,
143-
id: selectableActions.selectableActionId ?? `card-selectable-${uniqueId}`,
144-
name: selectableActions.name,
145-
isDisabled: isCardDisabled,
146-
onChange: selectableActions.onChange,
147-
isChecked: selectableActions.isChecked ?? isSelected,
148-
...selectableActions.selectableActionProps
149-
});
124+
const isClickableOnlyCard = isClickable && !isSelectable;
125+
if (
126+
(isClickableOnlyCard || isSelectable) &&
127+
!selectableActions?.selectableActionAriaLabel &&
128+
!selectableActions?.selectableActionAriaLabelledby
129+
) {
130+
// eslint-disable-next-line no-console
131+
console.error(
132+
`Card: ${isClickableOnlyCard ? 'Clickable-only cards' : 'Cards with a selectable input'} must have either the selectableActions.selectableActionAriaLabel or selectableActions.selectableActionAriaLabelledby prop passed in order to provide an accessible name to the clickable element.`
133+
);
134+
}
150135

151-
const isClickableLinkCard = selectableActions?.to !== undefined;
152-
const ClickableCardComponent = isClickableLinkCard ? 'a' : 'button';
153-
const getClickableProps = () => {
154-
const isDisabledLinkCard = isCardDisabled && isClickableLinkCard;
155-
const baseProps = {
156-
className: css(
157-
'pf-v6-c-card__clickable-action',
158-
isDisabledLinkCard && styles.modifiers.disabled,
159-
selectableActions?.isHidden && 'pf-v6-screen-reader'
160-
),
161-
id: selectableActions.selectableActionId,
136+
const SelectableCardInput = selectableActions?.variant === 'single' ? Radio : Checkbox;
137+
const getSelectableProps = () => ({
138+
className: css('pf-m-standalone'),
139+
inputClassName: css(selectableActions?.isHidden && 'pf-v6-screen-reader'),
140+
label: <></>,
162141
'aria-label': selectableActions.selectableActionAriaLabel,
163142
'aria-labelledby': selectableActions.selectableActionAriaLabelledby,
143+
id: selectableActions.selectableActionId ?? `card-selectable-${randomId}`,
144+
name: selectableActions.name,
145+
isDisabled: isCardDisabled,
146+
onChange: selectableActions.onChange,
147+
isChecked: selectableActions.isChecked ?? isSelected,
164148
...selectableActions.selectableActionProps
165-
};
149+
});
166150

167-
if (isClickableLinkCard) {
168-
return {
169-
...baseProps,
170-
href: selectableActions.to,
171-
...(isCardDisabled && { tabIndex: -1, 'aria-disabled': true }),
172-
...(selectableActions.isExternalLink && { target: '_blank' })
151+
const isClickableLinkCard = selectableActions?.to !== undefined;
152+
const ClickableCardComponent = isClickableLinkCard ? 'a' : 'button';
153+
const getClickableProps = () => {
154+
const isDisabledLinkCard = isCardDisabled && isClickableLinkCard;
155+
const baseProps = {
156+
className: css(
157+
'pf-v6-c-card__clickable-action',
158+
isDisabledLinkCard && styles.modifiers.disabled,
159+
selectableActions?.isHidden && 'pf-v6-screen-reader'
160+
),
161+
id: selectableActions.selectableActionId,
162+
'aria-label': selectableActions.selectableActionAriaLabel,
163+
'aria-labelledby': selectableActions.selectableActionAriaLabelledby,
164+
...selectableActions.selectableActionProps
173165
};
174-
}
175166

176-
return { ...baseProps, type: 'button', disabled: isCardDisabled, onClick: selectableActions.onClickAction };
177-
};
167+
if (isClickableLinkCard) {
168+
return {
169+
...baseProps,
170+
href: selectableActions.to,
171+
...(isCardDisabled && { tabIndex: -1, 'aria-disabled': true }),
172+
...(selectableActions.isExternalLink && { target: '_blank' })
173+
};
174+
}
178175

179-
return (
180-
<div
181-
className={css(styles.cardHeader, isToggleRightAligned && styles.modifiers.toggleRight, className)}
182-
id={id}
183-
{...props}
184-
>
185-
{onExpand && !isToggleRightAligned && cardHeaderToggle}
186-
{(actions || (selectableActions && (isClickable || isSelectable))) && (
187-
<CardActions
188-
className={actions?.className}
189-
hasNoOffset={actions?.hasNoOffset || selectableActions?.hasNoOffset}
190-
>
191-
{actions?.actions}
192-
{selectableActions && (isClickable || isSelectable) && (
193-
<CardSelectableActions className={selectableActions?.className}>
194-
{isSelectable && <SelectableCardInput {...getSelectableProps()} />}
195-
{isClickableOnlyCard && <ClickableCardComponent {...getClickableProps()} />}
196-
</CardSelectableActions>
197-
)}
198-
</CardActions>
199-
)}
200-
{children && <CardHeaderMain>{children}</CardHeaderMain>}
201-
{onExpand && isToggleRightAligned && cardHeaderToggle}
202-
</div>
203-
);
204-
}}
205-
</CardContext.Consumer>
206-
);
207-
};
176+
return { ...baseProps, type: 'button', disabled: isCardDisabled, onClick: selectableActions.onClickAction };
177+
};
178+
179+
return (
180+
<div
181+
className={css(styles.cardHeader, isToggleRightAligned && styles.modifiers.toggleRight, className)}
182+
id={id}
183+
{...props}
184+
>
185+
{onExpand && !isToggleRightAligned && cardHeaderToggle}
186+
{(actions || (selectableActions && (isClickable || isSelectable))) && (
187+
<CardActions
188+
className={actions?.className}
189+
hasNoOffset={actions?.hasNoOffset || selectableActions?.hasNoOffset}
190+
>
191+
{actions?.actions}
192+
{selectableActions && (isClickable || isSelectable) && (
193+
<CardSelectableActions className={selectableActions?.className}>
194+
{isSelectable && <SelectableCardInput {...getSelectableProps()} />}
195+
{isClickableOnlyCard && <ClickableCardComponent {...getClickableProps()} />}
196+
</CardSelectableActions>
197+
)}
198+
</CardActions>
199+
)}
200+
{children && <CardHeaderMain>{children}</CardHeaderMain>}
201+
{onExpand && isToggleRightAligned && cardHeaderToggle}
202+
</div>
203+
);
204+
}}
205+
</CardContext.Consumer>
206+
)}
207+
</GenerateId>
208+
);
208209
CardHeader.displayName = 'CardHeader';

packages/react-core/src/components/DataList/DataListCheck.tsx

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as React from 'react';
22
import { css } from '@patternfly/react-styles';
33
import styles from '@patternfly/react-styles/css/components/DataList/data-list';
44
import { Checkbox, CheckboxProps } from '../Checkbox';
5+
import { GenerateId } from '../../helpers/GenerateId/GenerateId';
56

67
export interface DataListCheckProps extends Omit<CheckboxProps, 'ref' | 'id'> {
78
/** Id of the DataList checkbox. */
@@ -46,21 +47,23 @@ export const DataListCheck: React.FunctionComponent<DataListCheckProps> = ({
4647
otherControls = false,
4748
...props
4849
}: DataListCheckProps) => {
49-
const uniqueId = React.useId();
50-
5150
const check = (
5251
<div className={css(styles.dataListCheck)}>
53-
<Checkbox
54-
id={id ?? `datalist-check-${uniqueId}`}
55-
isChecked={isChecked}
56-
checked={checked}
57-
defaultChecked={defaultChecked}
58-
onChange={onChange}
59-
aria-invalid={!isValid}
60-
isDisabled={isDisabled}
61-
isLabelWrapped
62-
{...props}
63-
/>
52+
<GenerateId>
53+
{(randomId) => (
54+
<Checkbox
55+
id={id ?? `datalist-check-${randomId}`}
56+
isChecked={isChecked}
57+
checked={checked}
58+
defaultChecked={defaultChecked}
59+
onChange={onChange}
60+
aria-invalid={!isValid}
61+
isDisabled={isDisabled}
62+
isLabelWrapped
63+
{...props}
64+
/>
65+
)}
66+
</GenerateId>
6467
</div>
6568
);
6669
return (

0 commit comments

Comments
 (0)