Skip to content

Commit 7b37292

Browse files
committed
fix: ListItem disabled states
The ListItem will now correctly apply the disabled states as needed and also prevent the item from being clicked while disabled.
1 parent 0f67a4c commit 7b37292

File tree

4 files changed

+59
-3
lines changed

4 files changed

+59
-3
lines changed

packages/list/src/SimpleListItem.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable jsx-a11y/click-events-have-key-events, jsx-a11y/role-supports-aria-props */
12
import React, { forwardRef } from "react";
23
import cn from "classnames";
34
import { bem } from "@react-md/utils";
@@ -36,6 +37,8 @@ const SimpleListItem = forwardRef<HTMLLIElement, SimpleListItemProps>(
3637
height: propHeight = "auto",
3738
threeLines = false,
3839
clickable = false,
40+
onClick,
41+
disabled = false,
3942
...props
4043
},
4144
ref
@@ -48,19 +51,25 @@ const SimpleListItem = forwardRef<HTMLLIElement, SimpleListItemProps>(
4851
rightAddonType,
4952
secondaryText,
5053
});
54+
const { "aria-disabled": ariaDisabled } = props;
55+
const isDisabled =
56+
disabled || ariaDisabled === "true" || ariaDisabled === true;
5157

5258
return (
5359
<li
5460
{...props}
61+
aria-disabled={isDisabled || undefined}
5562
ref={ref}
5663
className={cn(
5764
block({
5865
[height]: height !== "auto" && height !== "normal",
5966
"three-lines": threeLines,
6067
clickable,
68+
disabled: isDisabled,
6169
}),
6270
className
6371
)}
72+
onClick={isDisabled ? undefined : onClick}
6473
>
6574
<ListItemChildren
6675
textClassName={textClassName}
@@ -126,6 +135,7 @@ if (process.env.NODE_ENV !== "production") {
126135
rightAddonPosition: PropTypes.oneOf(["top", "middle", "bottom"]),
127136
forceAddonWrap: PropTypes.bool,
128137
children: PropTypes.node,
138+
onClick: PropTypes.func,
129139
};
130140
} catch (e) {}
131141
}

packages/list/src/__tests__/ListItem.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from "react";
2-
import { render } from "@testing-library/react";
2+
import { render, fireEvent } from "@testing-library/react";
33

44
import ListItem from "../ListItem";
55

@@ -11,4 +11,22 @@ describe("ListItem", () => {
1111
rerender(<ListItem leftAddon={<span>Left Icon</span>}>Content</ListItem>);
1212
expect(container).toMatchSnapshot();
1313
});
14+
15+
it('should correctly "polyfill" the disabled behavior by preventing click events when disabled', () => {
16+
const onClick = jest.fn();
17+
const props = { children: "Content", onClick };
18+
const { rerender, getByRole } = render(<ListItem {...props} disabled />);
19+
20+
const item = getByRole("button");
21+
expect(item).toHaveAttribute("aria-disabled", "true");
22+
expect(item.className).toContain("rmd-list-item--disabled");
23+
fireEvent.click(item);
24+
expect(onClick).not.toBeCalled();
25+
26+
rerender(<ListItem {...props} aria-disabled />);
27+
expect(item).toHaveAttribute("aria-disabled", "true");
28+
expect(item.className).toContain("rmd-list-item--disabled");
29+
fireEvent.click(item);
30+
expect(onClick).not.toBeCalled();
31+
});
1432
});

packages/list/src/__tests__/SimpleListItem.tsx

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from "react";
2-
import { render } from "@testing-library/react";
2+
import { render, fireEvent } from "@testing-library/react";
33

44
import SimpleListItem from "../SimpleListItem";
55

@@ -13,4 +13,30 @@ describe("SimpleListItem", () => {
1313
rerender(<SimpleListItem {...props} leftAddon={<span>Left</span>} />);
1414
expect(container).toMatchSnapshot();
1515
});
16+
17+
it('should correctly "polyfill" the disabled behavior by preventing click events when disabled', () => {
18+
const onClick = jest.fn();
19+
const props = { children: "Content", onClick, clickable: true };
20+
const { rerender, getByText } = render(
21+
<SimpleListItem {...props} disabled />
22+
);
23+
24+
const item = getByText(props.children);
25+
expect(item).toHaveAttribute("aria-disabled", "true");
26+
expect(item.className).toContain("rmd-list-item--disabled");
27+
fireEvent.click(item);
28+
expect(onClick).not.toBeCalled();
29+
30+
rerender(<SimpleListItem {...props} aria-disabled />);
31+
expect(item).toHaveAttribute("aria-disabled", "true");
32+
expect(item.className).toContain("rmd-list-item--disabled");
33+
fireEvent.click(item);
34+
expect(onClick).not.toBeCalled();
35+
36+
rerender(<SimpleListItem {...props} aria-disabled={false} />);
37+
expect(item).not.toHaveAttribute("aria-disabled");
38+
expect(item.className).not.toContain("rmd-list-item--disabled");
39+
fireEvent.click(item);
40+
expect(onClick).toBeCalled();
41+
});
1642
});

packages/list/src/_mixins.scss

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,10 @@
153153
@include rmd-states-surface;
154154
}
155155

156-
&[aria-disabled] {
156+
&--disabled {
157157
@include rmd-theme(color, text-disabled-on-background);
158+
159+
pointer-events: none;
158160
}
159161

160162
&--link {

0 commit comments

Comments
 (0)