Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 8a2e386

Browse files
authored
Add disabled button state to rich text editor (#9930)
* add disabled css state * conditionally apply disabled css state * hides disabled tooltips
1 parent b47588f commit 8a2e386

File tree

3 files changed

+46
-15
lines changed

3 files changed

+46
-15
lines changed

res/css/views/rooms/wysiwyg_composer/components/_FormattingButtons.pcss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ limitations under the License.
5050
}
5151
}
5252

53+
.mx_FormattingButtons_disabled {
54+
.mx_FormattingButtons_Icon {
55+
color: $quinary-content;
56+
}
57+
}
58+
5359
.mx_FormattingButtons_Icon {
5460
--size: 16px;
5561
height: var(--size);

src/components/views/rooms/wysiwyg_composer/components/FormattingButtons.tsx

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ limitations under the License.
1515
*/
1616

1717
import React, { MouseEventHandler, ReactNode } from "react";
18-
import { FormattingFunctions, AllActionStates } from "@matrix-org/matrix-wysiwyg";
18+
import { FormattingFunctions, AllActionStates, ActionState } from "@matrix-org/matrix-wysiwyg";
1919
import classNames from "classnames";
2020

2121
import { Icon as BoldIcon } from "../../../../../../res/img/element-icons/room/composer/bold.svg";
@@ -53,21 +53,23 @@ function Tooltip({ label, keyCombo }: TooltipProps): JSX.Element {
5353

5454
interface ButtonProps extends TooltipProps {
5555
icon: ReactNode;
56-
isActive: boolean;
56+
actionState: ActionState;
5757
onClick: MouseEventHandler<HTMLButtonElement>;
5858
}
5959

60-
function Button({ label, keyCombo, onClick, isActive, icon }: ButtonProps): JSX.Element {
60+
function Button({ label, keyCombo, onClick, actionState, icon }: ButtonProps): JSX.Element {
6161
return (
6262
<AccessibleTooltipButton
6363
element="button"
6464
onClick={onClick as (e: ButtonEvent) => void}
6565
title={label}
6666
className={classNames("mx_FormattingButtons_Button", {
67-
mx_FormattingButtons_active: isActive,
68-
mx_FormattingButtons_Button_hover: !isActive,
67+
mx_FormattingButtons_active: actionState === "reversed",
68+
mx_FormattingButtons_Button_hover: actionState === "enabled",
69+
mx_FormattingButtons_disabled: actionState === "disabled",
6970
})}
7071
tooltip={keyCombo && <Tooltip label={label} keyCombo={keyCombo} />}
72+
forceHide={actionState === "disabled"}
7173
alignment={Alignment.Top}
7274
>
7375
{icon}
@@ -85,53 +87,53 @@ export function FormattingButtons({ composer, actionStates }: FormattingButtonsP
8587
return (
8688
<div className="mx_FormattingButtons">
8789
<Button
88-
isActive={actionStates.bold === "reversed"}
90+
actionState={actionStates.bold}
8991
label={_td("Bold")}
9092
keyCombo={{ ctrlOrCmdKey: true, key: "b" }}
9193
onClick={() => composer.bold()}
9294
icon={<BoldIcon className="mx_FormattingButtons_Icon" />}
9395
/>
9496
<Button
95-
isActive={actionStates.italic === "reversed"}
97+
actionState={actionStates.italic}
9698
label={_td("Italic")}
9799
keyCombo={{ ctrlOrCmdKey: true, key: "i" }}
98100
onClick={() => composer.italic()}
99101
icon={<ItalicIcon className="mx_FormattingButtons_Icon" />}
100102
/>
101103
<Button
102-
isActive={actionStates.underline === "reversed"}
104+
actionState={actionStates.underline}
103105
label={_td("Underline")}
104106
keyCombo={{ ctrlOrCmdKey: true, key: "u" }}
105107
onClick={() => composer.underline()}
106108
icon={<UnderlineIcon className="mx_FormattingButtons_Icon" />}
107109
/>
108110
<Button
109-
isActive={actionStates.strikeThrough === "reversed"}
111+
actionState={actionStates.strikeThrough}
110112
label={_td("Strikethrough")}
111113
onClick={() => composer.strikeThrough()}
112114
icon={<StrikeThroughIcon className="mx_FormattingButtons_Icon" />}
113115
/>
114116
<Button
115-
isActive={actionStates.unorderedList === "reversed"}
117+
actionState={actionStates.unorderedList}
116118
label={_td("Bulleted list")}
117119
onClick={() => composer.unorderedList()}
118120
icon={<BulletedListIcon className="mx_FormattingButtons_Icon" />}
119121
/>
120122
<Button
121-
isActive={actionStates.orderedList === "reversed"}
123+
actionState={actionStates.orderedList}
122124
label={_td("Numbered list")}
123125
onClick={() => composer.orderedList()}
124126
icon={<NumberedListIcon className="mx_FormattingButtons_Icon" />}
125127
/>
126128
<Button
127-
isActive={actionStates.inlineCode === "reversed"}
129+
actionState={actionStates.inlineCode}
128130
label={_td("Code")}
129131
keyCombo={{ ctrlOrCmdKey: true, key: "e" }}
130132
onClick={() => composer.inlineCode()}
131133
icon={<InlineCodeIcon className="mx_FormattingButtons_Icon" />}
132134
/>
133135
<Button
134-
isActive={actionStates.link === "reversed"}
136+
actionState={actionStates.link}
135137
label={_td("Link")}
136138
onClick={() => openLinkModal(composer, composerContext, actionStates.link === "reversed")}
137139
icon={<LinkIcon className="mx_FormattingButtons_Icon" />}

test/components/views/rooms/wysiwyg_composer/components/FormattingButtons-test.tsx

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ const renderComponent = (props = {}) => {
6262
const classes = {
6363
active: "mx_FormattingButtons_active",
6464
hover: "mx_FormattingButtons_Button_hover",
65+
disabled: "mx_FormattingButtons_disabled",
6566
};
6667

6768
describe("FormattingButtons", () => {
@@ -87,6 +88,16 @@ describe("FormattingButtons", () => {
8788
});
8889
});
8990

91+
it("Each button should have disabled class when disabled", () => {
92+
const disabledActionStates = createActionStates("disabled");
93+
renderComponent({ actionStates: disabledActionStates });
94+
95+
Object.values(testCases).forEach((testCase) => {
96+
const { label } = testCase;
97+
expect(screen.getByLabelText(label)).toHaveClass(classes.disabled);
98+
});
99+
});
100+
90101
it("Should call wysiwyg function on button click", async () => {
91102
renderComponent();
92103

@@ -98,14 +109,26 @@ describe("FormattingButtons", () => {
98109
}
99110
});
100111

101-
it("Each button should display the tooltip on mouse over", async () => {
112+
it("Each button should display the tooltip on mouse over when not disabled", async () => {
102113
renderComponent();
103114

104115
for (const testCase of Object.values(testCases)) {
105116
const { label } = testCase;
106117

107118
await userEvent.hover(screen.getByLabelText(label));
108-
expect(await screen.findByText(label)).toBeTruthy();
119+
expect(screen.getByText(label)).toBeInTheDocument();
120+
}
121+
});
122+
123+
it("Each button should not display the tooltip on mouse over when disabled", async () => {
124+
const disabledActionStates = createActionStates("disabled");
125+
renderComponent({ actionStates: disabledActionStates });
126+
127+
for (const testCase of Object.values(testCases)) {
128+
const { label } = testCase;
129+
130+
await userEvent.hover(screen.getByLabelText(label));
131+
expect(screen.queryByText(label)).not.toBeInTheDocument();
109132
}
110133
});
111134

0 commit comments

Comments
 (0)