Skip to content

Commit

Permalink
fix(Input): adornment tooltip when disabled (#4423)
Browse files Browse the repository at this point in the history
  • Loading branch information
zettca authored Nov 13, 2024
1 parent 865d63a commit de9c471
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 80 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ lerna-debug.log*
.env*

# Build
build
dist
bin
packages/icons/sprites
Expand Down
12 changes: 9 additions & 3 deletions packages/core/src/Button/Button.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import { theme, type HvSize } from "@hitachivantara/uikit-styles";
import { outlineStyles } from "../utils/focusUtils";

export const { staticClasses, useClasses } = createClasses("HvButton", {
/**
* Classes applied to the root element
*/
/** applied to the root element */
root: {
display: "inline-flex",
alignItems: "center",
Expand Down Expand Up @@ -35,17 +33,20 @@ export const { staticClasses, useClasses } = createClasses("HvButton", {
borderRadius: `var(--radius, ${theme.radii.base})`,
padding: theme.spacing(0, "sm"),
},
/** applied to the _left_ icon container */
startIcon: {
marginLeft: theme.spacing(-1),
marginTop: -1,
marginBottom: -1,
},
/** applied to the _right_ icon container */
endIcon: {
marginRight: theme.spacing(-1),
marginTop: -1,
marginBottom: -1,
},
focusVisible: {},
/** applied to the root element when disabled */
disabled: {
cursor: "not-allowed",
color: theme.colors.secondary_60,
Expand All @@ -56,6 +57,7 @@ export const { staticClasses, useClasses } = createClasses("HvButton", {
borderColor: "transparent",
},
},
/** applied to the root element when is icon-only */
icon: {
margin: 0,
padding: 0,
Expand All @@ -64,6 +66,7 @@ export const { staticClasses, useClasses } = createClasses("HvButton", {
margin: -1,
},
},
/** applied to the root element when using the `contained` variant */
contained: {
color: theme.colors.atmo1, // `color-contrast(var(--color) vs ${colors.atmo1}, ${colors.base_light}, ${colors.base_dark})`,
backgroundColor: "var(--color)",
Expand All @@ -76,10 +79,13 @@ export const { staticClasses, useClasses } = createClasses("HvButton", {
},
},
},
/** applied to the root element when using the `subtle` variant */
subtle: {
borderColor: "currentcolor",
},
/** applied to the root element when using the `ghost` variant */
ghost: {},
/** applied to the root element when using the `semantic` variant */
semantic: {
color: theme.colors.base_dark,
backgroundColor: "transparent",
Expand Down
140 changes: 70 additions & 70 deletions packages/core/src/Forms/Adornment/Adornment.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { forwardRef, useContext } from "react";
import { type ExtractNames } from "@hitachivantara/uikit-react-utils";
import {
useDefaultProps,
type ExtractNames,
} from "@hitachivantara/uikit-react-utils";

import { HvButtonBase } from "../../ButtonBase";
import { HvBaseProps } from "../../types/generic";
import {
HvFormElementContext,
Expand Down Expand Up @@ -46,77 +50,73 @@ export interface HvAdornmentProps
export const HvAdornment = forwardRef<
HTMLDivElement | HTMLButtonElement,
HvAdornmentProps
>(
(
{
id,
classes: classesProp,
className,
icon,
showWhen = undefined,
onClick,
isVisible = undefined,
...others
},
ref,
) => {
const { classes, cx } = useClasses(classesProp);
>((props, ref) => {
const {
id,
classes: classesProp,
className,
icon,
showWhen = undefined,
onClick,
isVisible = undefined,
...others
} = useDefaultProps("HvAdornment", props);
const { classes, cx } = useClasses(classesProp);

const { elementStatus = "", elementDisabled } =
useContext(HvFormElementContext);
const { elementStatus = "", elementDisabled } =
useContext(HvFormElementContext);

const { input } = useContext(HvFormElementDescriptorsContext);
const { input } = useContext(HvFormElementDescriptorsContext);

const displayIcon =
isVisible ?? (showWhen === undefined || elementStatus === showWhen);
const displayIcon =
isVisible ?? (showWhen === undefined || elementStatus === showWhen);

const isClickable = !!onClick;
const isClickable = !!onClick;

return isClickable ? (
<button
id={id}
ref={ref as React.ForwardedRef<HTMLButtonElement>}
type="button"
tabIndex={-1}
aria-controls={input?.[0]?.id}
className={cx(
classes.root,
classes.adornment,
classes.adornmentButton,
{
[classes.hideIcon]: !displayIcon,
[classes.disabled]: elementDisabled,
},
className,
)}
onClick={onClick}
onMouseDown={(event) => event.preventDefault()}
onKeyDown={noop}
disabled={elementDisabled}
aria-disabled={elementDisabled}
{...others}
>
<div className={classes.icon}>{icon}</div>
</button>
) : (
<div
id={id}
ref={ref as React.ForwardedRef<HTMLDivElement>}
className={cx(
classes.root,
classes.adornment,
classes.adornmentIcon,
{
[classes.hideIcon]: !displayIcon,
[classes.disabled]: elementDisabled,
},
className,
)}
role="presentation"
{...others}
>
<div className={classes.icon}>{icon}</div>
</div>
);
},
);
return isClickable ? (
<HvButtonBase
id={id}
focusableWhenDisabled
ref={ref as React.ForwardedRef<HTMLButtonElement>}
type="button"
tabIndex={-1}
aria-controls={input?.[0]?.id}
className={cx(
classes.root,
classes.adornment,
classes.adornmentButton,
{
[classes.hideIcon]: !displayIcon,
[classes.disabled]: elementDisabled,
},
className,
)}
onClick={onClick}
onMouseDown={(event) => event.preventDefault()}
onKeyDown={noop}
disabled={elementDisabled}
{...others}
>
<div className={classes.icon}>{icon}</div>
</HvButtonBase>
) : (
<div
id={id}
ref={ref as React.ForwardedRef<HTMLDivElement>}
className={cx(
classes.root,
classes.adornment,
classes.adornmentIcon,
{
[classes.hideIcon]: !displayIcon,
[classes.disabled]: elementDisabled,
},
className,
)}
role="presentation"
{...others}
>
<div className={classes.icon}>{icon}</div>
</div>
);
});
8 changes: 3 additions & 5 deletions packages/core/src/Input/Input.styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,9 @@ export const { staticClasses, useClasses } = createClasses("HvInput", {
},
icon: { width: "30px", height: "30px" },
adornmentButton: {
backgroundColor: "transparent",
border: "none",
padding: 0,
margin: 0,
cursor: "pointer",
":focus-visible,:hover": {
backgroundColor: "transparent",
},
},
iconClear: { display: "none" },
hasSuggestions: {},
Expand Down
6 changes: 4 additions & 2 deletions packages/core/src/Input/Input.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ describe("Input", () => {
);

expect(screen.getByRole("searchbox")).toBeDisabled();
expect(screen.getByLabelText("Search")).toBeDisabled(); // role can't be used since the parent has aria-hidden
const adornment = screen.getByLabelText("Search"); // role can't be used since the parent has aria-hidden
expect(adornment).toHaveAttribute("aria-disabled", "true");
});

it("renders the adornment as disabled for the password when the input is disabled", () => {
Expand All @@ -79,7 +80,8 @@ describe("Input", () => {
);

expect(screen.getByLabelText("My input")).toBeDisabled(); // can't find by role searchbox since password inputs don't have a role...
expect(screen.getByLabelText("Reveal password")).toBeDisabled(); // role can't be used since the parent has aria-hidden
const adornment = screen.getByLabelText("Reveal password"); // roles can't be used since the parent has aria-hidden
expect(adornment).toHaveAttribute("aria-disabled", "true");
});

it("does not trigger the suggestions on focus by default", async () => {
Expand Down

0 comments on commit de9c471

Please sign in to comment.