Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Label): allow clickable labels to be disabled #10199

Merged
merged 5 commits into from
Mar 29, 2024
Merged
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
21 changes: 16 additions & 5 deletions packages/react-core/src/components/Label/Label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export interface LabelProps extends React.HTMLProps<HTMLSpanElement> {
variant?: 'outline' | 'filled';
/** Flag indicating the label is compact. */
isCompact?: boolean;
/** Flag indicating the label is disabled. Works only on clickable labels, so either href or onClick props must be passed in. */
isDisabled?: boolean;
/** @beta Flag indicating the label is editable. */
isEditable?: boolean;
/** @beta Additional props passed to the editable label text div. Optionally passing onInput and onBlur callbacks will allow finer custom text input control. */
Expand Down Expand Up @@ -91,6 +93,7 @@ export const Label: React.FunctionComponent<LabelProps> = ({
color = 'grey',
variant = 'filled',
isCompact = false,
isDisabled = false,
isEditable = false,
editableProps,
textMaxWidth,
Expand Down Expand Up @@ -198,21 +201,22 @@ export const Label: React.FunctionComponent<LabelProps> = ({
}
};

const LabelComponent = (isOverflowLabel ? 'button' : 'span') as any;
const isClickableDisabled = (href || onLabelClick) && isDisabled;

const defaultButton = (
const defaultCloseButton = (
<Button
type="button"
variant="plain"
onClick={onClose}
aria-label={closeBtnAriaLabel || `Close ${children}`}
{...(isClickableDisabled && { isDisabled: true })}
{...closeBtnProps}
>
<TimesIcon />
</Button>
);

const button = <span className={css(styles.labelActions)}>{closeBtn || defaultButton}</span>;
const closeButton = <span className={css(styles.labelActions)}>{closeBtn || defaultCloseButton}</span>;
const textRef = React.createRef<any>();
// ref to apply tooltip when rendered is used
const componentRef = React.useRef();
Expand Down Expand Up @@ -268,6 +272,8 @@ export const Label: React.FunctionComponent<LabelProps> = ({
className: css(styles.labelContent),
...(isTooltipVisible && { tabIndex: 0 }),
...(href && { href }),
// Need to prevent onClick since aria-disabled won't prevent AT from triggering the link
...(href && isDisabled && { onClick: (event: MouseEvent) => event.preventDefault() }),
...(isButton && clickableLabelProps),
...(isEditable && {
ref: editableButtonRef,
Expand All @@ -276,7 +282,9 @@ export const Label: React.FunctionComponent<LabelProps> = ({
e.stopPropagation();
},
...editableProps
})
}),
...(isClickableDisabled && isButton && { disabled: true }),
...(isClickableDisabled && href && { tabindex: -1, 'aria-disabled': true })
};

let labelComponentChild = (
Expand All @@ -302,11 +310,14 @@ export const Label: React.FunctionComponent<LabelProps> = ({
);
}

const LabelComponent = (isOverflowLabel ? 'button' : 'span') as any;

return (
<LabelComponent
{...props}
className={css(
styles.label,
isClickableDisabled && styles.modifiers.disabled,
colorStyles[color],
variant === 'outline' && styles.modifiers.outline,
isOverflowLabel && styles.modifiers.overflow,
Expand All @@ -318,7 +329,7 @@ export const Label: React.FunctionComponent<LabelProps> = ({
onClick={isOverflowLabel ? onLabelClick : undefined}
>
{!isEditableActive && labelComponentChild}
{!isEditableActive && onClose && button}
{!isEditableActive && onClose && closeButton}
{isEditableActive && (
<input
className={css(styles.labelContent)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,27 @@ export const LabelCompact: React.FunctionComponent = () => (
</Label>{' '}
<Label isCompact href="#compact" onClose={() => Function.prototype}>
Compact link removable
</Label>
</Label>{' '}
<Label isCompact onClick={() => Function.prototype}>
Compact clickable
</Label>{' '}
<Label isCompact onClick={() => Function.prototype} onClose={() => Function.prototype}>
Compact clickable removable
</Label>{' '}
<Label isCompact icon={<InfoCircleIcon />} onClose={() => Function.prototype} textMaxWidth="16ch">
Compact label with icon that overflows
</Label>{' '}
<Label isDisabled isCompact href="#compact" onClose={() => Function.prototype} icon={<InfoCircleIcon />}>
Compact link removable (disabled)
</Label>{' '}
<Label
isDisabled
isCompact
onClick={() => Function.prototype}
onClose={() => Function.prototype}
icon={<InfoCircleIcon />}
>
Compact clickable removable (disabled)
</Label>
</React.Fragment>
);
122 changes: 106 additions & 16 deletions packages/react-core/src/components/Label/examples/LabelFilled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,19 @@ export const LabelFilled: React.FunctionComponent = () => {
<Label href="#filled">Grey link</Label>{' '}
<Label href="#filled" onClose={() => Function.prototype}>
Grey link removable
</Label>
</Label>{' '}
<Label onClick={() => logColor('grey')}>Grey clickable</Label>{' '}
<Label onClick={() => logColor('grey')} onClose={() => Function.prototype}>
Grey clickable removable
</Label>
</Label>{' '}
<Label icon={<InfoCircleIcon />} onClose={() => Function.prototype} textMaxWidth="16ch">
Grey label with icon that overflows
</Label>{' '}
<Label isDisabled icon={<InfoCircleIcon />} href="#filled" onClose={() => Function.prototype}>
Grey link removable (disabled)
</Label>{' '}
<Label isDisabled icon={<InfoCircleIcon />} onClick={() => logColor('grey')} onClose={() => Function.prototype}>
Grey clickable removable (disabled)
</Label>
<br />
<br />
Expand All @@ -42,15 +48,27 @@ export const LabelFilled: React.FunctionComponent = () => {
</Label>{' '}
<Label color="blue" href="#filled" onClose={() => Function.prototype}>
Blue link removable
</Label>
</Label>{' '}
<Label color="blue" onClick={() => logColor('blue')}>
Blue clickable
</Label>{' '}
<Label color="blue" onClick={() => logColor('blue')} onClose={() => Function.prototype}>
Blue clickable removable
</Label>
</Label>{' '}
<Label color="blue" icon={<InfoCircleIcon />} onClose={() => Function.prototype} textMaxWidth="16ch">
Blue label with icon that overflows
</Label>{' '}
<Label color="blue" isDisabled icon={<InfoCircleIcon />} href="#filled" onClose={() => Function.prototype}>
Blue link removable (disabled)
</Label>{' '}
<Label
color="blue"
isDisabled
icon={<InfoCircleIcon />}
onClick={() => logColor('blue')}
onClose={() => Function.prototype}
>
Blue clickable removable (disabled)
</Label>
<br />
<br />
Expand All @@ -69,15 +87,27 @@ export const LabelFilled: React.FunctionComponent = () => {
</Label>{' '}
<Label color="green" href="#filled" onClose={() => Function.prototype}>
Green link removable
</Label>
</Label>{' '}
<Label color="green" onClick={() => logColor('green')}>
Green clickable
</Label>{' '}
<Label color="green" onClick={() => logColor('green')} onClose={() => Function.prototype}>
Green clickable removable
</Label>
</Label>{' '}
<Label color="green" icon={<InfoCircleIcon />} onClose={() => Function.prototype} textMaxWidth="16ch">
Green label with icon that overflows
</Label>{' '}
<Label color="green" isDisabled icon={<InfoCircleIcon />} href="#filled" onClose={() => Function.prototype}>
Green link removable (disabled)
</Label>{' '}
<Label
color="green"
isDisabled
icon={<InfoCircleIcon />}
onClick={() => logColor('green')}
onClose={() => Function.prototype}
>
Green clickable removable (disabled)
</Label>
<br />
<br />
Expand All @@ -96,15 +126,27 @@ export const LabelFilled: React.FunctionComponent = () => {
</Label>{' '}
<Label color="orange" href="#filled" onClose={() => Function.prototype}>
Orange link removable
</Label>
</Label>{' '}
<Label color="orange" onClick={() => logColor('orange')}>
Orange clickable
</Label>{' '}
<Label color="orange" onClick={() => logColor('orange')} onClose={() => Function.prototype}>
Orange clickable removable
</Label>
</Label>{' '}
<Label color="orange" icon={<InfoCircleIcon />} onClose={() => Function.prototype} textMaxWidth="16ch">
Orange label with icon that overflows
</Label>{' '}
<Label color="orange" isDisabled icon={<InfoCircleIcon />} href="#filled" onClose={() => Function.prototype}>
Orange link removable (disabled)
</Label>{' '}
<Label
color="orange"
isDisabled
icon={<InfoCircleIcon />}
onClick={() => logColor('orange')}
onClose={() => Function.prototype}
>
Orange clickable removable (disabled)
</Label>
<br />
<br />
Expand All @@ -123,15 +165,27 @@ export const LabelFilled: React.FunctionComponent = () => {
</Label>{' '}
<Label color="red" href="#filled" onClose={() => Function.prototype}>
Red link removable
</Label>
</Label>{' '}
<Label color="red" onClick={() => logColor('red')}>
Red clickable
</Label>{' '}
<Label color="red" onClick={() => logColor('red')} onClose={() => Function.prototype}>
Red clickable removable
</Label>
</Label>{' '}
<Label color="red" icon={<InfoCircleIcon />} onClose={() => Function.prototype} textMaxWidth="16ch">
Red label with icon that overflows
</Label>{' '}
<Label color="red" isDisabled icon={<InfoCircleIcon />} href="#filled" onClose={() => Function.prototype}>
Red link removable (disabled)
</Label>{' '}
<Label
color="red"
isDisabled
icon={<InfoCircleIcon />}
onClick={() => logColor('red')}
onClose={() => Function.prototype}
>
Red clickable removable (disabled)
</Label>
<br />
<br />
Expand All @@ -150,15 +204,27 @@ export const LabelFilled: React.FunctionComponent = () => {
</Label>{' '}
<Label color="purple" href="#filled" onClose={() => Function.prototype}>
Purple link removable
</Label>
</Label>{' '}
<Label color="purple" onClick={() => logColor('purple')}>
Purple clickable
</Label>{' '}
<Label color="purple" onClick={() => logColor('purple')} onClose={() => Function.prototype}>
Purple clickable removable
</Label>
</Label>{' '}
<Label color="purple" icon={<InfoCircleIcon />} onClose={() => Function.prototype} textMaxWidth="16ch">
Purple label with icon that overflows
</Label>{' '}
<Label color="purple" isDisabled icon={<InfoCircleIcon />} href="#filled" onClose={() => Function.prototype}>
Purple link removable (disabled)
</Label>{' '}
<Label
color="purple"
isDisabled
icon={<InfoCircleIcon />}
onClick={() => logColor('purple')}
onClose={() => Function.prototype}
>
Purple clickable removable (disabled)
</Label>
<br />
<br />
Expand All @@ -177,15 +243,27 @@ export const LabelFilled: React.FunctionComponent = () => {
</Label>{' '}
<Label color="cyan" href="#filled" onClose={() => Function.prototype}>
Cyan link removable
</Label>
</Label>{' '}
<Label color="cyan" onClick={() => logColor('cyan')}>
Cyan clickable
</Label>{' '}
<Label color="cyan" onClick={() => logColor('cyan')} onClose={() => Function.prototype}>
Cyan clickable removable
</Label>
</Label>{' '}
<Label color="cyan" icon={<InfoCircleIcon />} onClose={() => Function.prototype} textMaxWidth="16ch">
Cyan label with icon that overflows
</Label>{' '}
<Label color="cyan" isDisabled icon={<InfoCircleIcon />} href="#filled" onClose={() => Function.prototype}>
Cyan link removable (disabled)
</Label>{' '}
<Label
color="cyan"
isDisabled
icon={<InfoCircleIcon />}
onClick={() => logColor('cyan')}
onClose={() => Function.prototype}
>
Cyan clickable removable (disabled)
</Label>
<br />
<br />
Expand All @@ -204,15 +282,27 @@ export const LabelFilled: React.FunctionComponent = () => {
</Label>{' '}
<Label color="gold" href="#filled" onClose={() => Function.prototype}>
Gold link removable
</Label>
</Label>{' '}
<Label color="gold" onClick={() => logColor('gold')}>
Gold clickable
</Label>{' '}
<Label color="gold" onClick={() => logColor('gold')} onClose={() => Function.prototype}>
Gold clickable removable
</Label>
</Label>{' '}
<Label color="gold" icon={<InfoCircleIcon />} onClose={() => Function.prototype} textMaxWidth="16ch">
Gold label with icon that overflows
</Label>{' '}
<Label color="gold" isDisabled icon={<InfoCircleIcon />} href="#filled" onClose={() => Function.prototype}>
Gold link removable (disabled)
</Label>{' '}
<Label
color="gold"
isDisabled
icon={<InfoCircleIcon />}
onClick={() => logColor('gold')}
onClose={() => Function.prototype}
>
Gold clickable removable (disabled)
</Label>
<br />
<br />
Expand Down
Loading
Loading