Skip to content

Commit 6ae7cbd

Browse files
fix(text-editor): fixes the formatting buttons when clicked to toggle without text selections
1 parent f8ee86f commit 6ae7cbd

File tree

6 files changed

+157
-1
lines changed

6 files changed

+157
-1
lines changed

src/components/text-editor/__internal__/plugins/ContentEditor/content-editor.component.tsx

+13-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,19 @@ const ContentEditor = ({
4747
aria-labelledby={`${namespace}-label`}
4848
className={`${namespace}-editable`}
4949
data-role={`${namespace}-editable`}
50-
onFocus={focusAtEnd}
50+
onFocus={(event: React.FocusEvent<HTMLDivElement> | undefined) => {
51+
/* istanbul ignore if */
52+
if (!event) return;
53+
54+
// If the related target is not a toolbar button, focus at the end of the editor
55+
/* istanbul ignore next */
56+
if (
57+
!event.relatedTarget ||
58+
!event.relatedTarget.classList.contains("toolbar-button")
59+
) {
60+
focusAtEnd(event);
61+
}
62+
}}
5163
/** The following are automatically added by Lexical but violate WCAG 4.1.2 Name, Role, Value and so have been overriden */
5264
aria-autocomplete={undefined}
5365
aria-readonly={undefined}

src/components/text-editor/__internal__/plugins/Toolbar/buttons/bold.component.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ const BoldButton = ({ isActive, namespace }: FormattingButtonProps) => {
4040
aria-pressed={isActive}
4141
data-role={`${namespace}-bold-button`}
4242
tabIndex={0}
43+
className="toolbar-button"
4344
/>
4445
);
4546
};

src/components/text-editor/__internal__/plugins/Toolbar/buttons/italic.component.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const ItalicButton = ({ isActive, namespace }: FormattingButtonProps) => {
3737
aria-pressed={isActive}
3838
data-role={`${namespace}-italic-button`}
3939
tabIndex={-1}
40+
className="toolbar-button"
4041
/>
4142
);
4243
};

src/components/text-editor/__internal__/plugins/Toolbar/buttons/list.component.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ const ListControls = ({ namespace }: { namespace: string }) => {
356356
aria-pressed={isULActive}
357357
data-role={`${namespace}-unordered-list-button`}
358358
tabIndex={-1}
359+
className="toolbar-button"
359360
/>
360361
<FormattingButton
361362
size="small"
@@ -369,6 +370,7 @@ const ListControls = ({ namespace }: { namespace: string }) => {
369370
aria-pressed={isOLActive}
370371
data-role={`${namespace}-ordered-list-button`}
371372
tabIndex={-1}
373+
className="toolbar-button"
372374
/>
373375
</>
374376
);

src/components/text-editor/text-editor.pw.tsx

+56
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,33 @@ test.describe("Functionality tests", () => {
453453
await boldButton.click();
454454
expect(await page.locator("strong").count()).toBe(0);
455455
});
456+
457+
test("applies and removes bold formatting to the editor directly", async ({
458+
mount,
459+
page,
460+
}) => {
461+
await mount(<TextEditorDefaultComponent value={unformattedValue} />);
462+
const textbox = await page.locator("div[role='textbox']");
463+
expect(await page.locator("strong").count()).toBe(0);
464+
expect(await page.locator("span[data-lexical-text='true']").count()).toBe(
465+
1,
466+
);
467+
await textbox.click();
468+
const boldButton = await page.locator(
469+
"button[data-role='pw-rte-bold-button']",
470+
);
471+
await boldButton.click();
472+
await textbox.click();
473+
await textbox.pressSequentially("This is some bold text", { delay: 100 });
474+
expect(await page.locator("strong").count()).toBe(1);
475+
await boldButton.click();
476+
await textbox.click();
477+
await textbox.pressSequentially(" and this is not", { delay: 100 });
478+
479+
expect(await page.locator("span[data-lexical-text='true']").count()).toBe(
480+
2,
481+
);
482+
});
456483
});
457484

458485
test.describe("Italic", () => {
@@ -473,6 +500,35 @@ test.describe("Functionality tests", () => {
473500
await italicButton.click();
474501
expect(await page.locator("em").count()).toBe(0);
475502
});
503+
504+
test("applies and removes italic formatting to the editor directly", async ({
505+
mount,
506+
page,
507+
}) => {
508+
await mount(<TextEditorDefaultComponent value={unformattedValue} />);
509+
const textbox = await page.locator("div[role='textbox']");
510+
expect(await page.locator("em").count()).toBe(0);
511+
expect(await page.locator("span[data-lexical-text='true']").count()).toBe(
512+
1,
513+
);
514+
await textbox.click();
515+
const italicButton = await page.locator(
516+
"button[data-role='pw-rte-italic-button']",
517+
);
518+
await italicButton.click();
519+
await textbox.click();
520+
await textbox.pressSequentially("This is some italic text", {
521+
delay: 100,
522+
});
523+
expect(await page.locator("em").count()).toBe(1);
524+
await italicButton.click();
525+
await textbox.click();
526+
await textbox.pressSequentially(" and this is not", { delay: 100 });
527+
528+
expect(await page.locator("span[data-lexical-text='true']").count()).toBe(
529+
2,
530+
);
531+
});
476532
});
477533

478534
test.describe("Ordered List", () => {

src/components/text-editor/text-editor.test.tsx

+84
Original file line numberDiff line numberDiff line change
@@ -488,3 +488,87 @@ test("should toggle the an indiviual list item's type when a list is active and
488488
await user.click(ulButton);
489489
expect(screen.queryAllByRole("list").length).toBe(1);
490490
});
491+
492+
describe("shortcut keys", () => {
493+
it("should toggle bold text when the bold shortcut is pressed", async () => {
494+
const user = userEvent.setup();
495+
const mockCancel = jest.fn();
496+
const mockSave = jest.fn();
497+
const value = JSON.stringify(initialValue);
498+
499+
// render the TextEditor component
500+
render(
501+
<TextEditor
502+
labelText="Example"
503+
onCancel={() => mockCancel()}
504+
onSave={() => mockSave()}
505+
value={value}
506+
characterLimit={20}
507+
/>,
508+
);
509+
510+
// Click the editor space and send a few key presses
511+
const editor = screen.getByRole(`textbox`);
512+
await user.click(editor);
513+
await user.keyboard(" not bold");
514+
515+
// expect the edited value to be visible
516+
expect(screen.getByText("Sample text not bold")).toBeInTheDocument();
517+
await user.tripleClick(editor);
518+
const commandKey =
519+
navigator.userAgent.indexOf("Mac") !== -1 ? "Meta" : "Control";
520+
await user.keyboard(`{${commandKey}>}b{/${commandKey}>}`);
521+
522+
// expect the text to be bold
523+
expect(screen.getByText("Sample text not bold")).toHaveStyle(
524+
"font-weight: bold",
525+
);
526+
await user.keyboard(`{${commandKey}>}b{/${commandKey}>}`);
527+
528+
// expect the text to be normal
529+
expect(screen.getByText("Sample text not bold")).not.toHaveStyle(
530+
"font-weight: bold",
531+
);
532+
});
533+
534+
it("should toggle italic text when the italic shortcut is pressed", async () => {
535+
const user = userEvent.setup();
536+
const mockCancel = jest.fn();
537+
const mockSave = jest.fn();
538+
const value = JSON.stringify(initialValue);
539+
540+
// render the TextEditor component
541+
render(
542+
<TextEditor
543+
labelText="Example"
544+
onCancel={() => mockCancel()}
545+
onSave={() => mockSave()}
546+
value={value}
547+
characterLimit={20}
548+
/>,
549+
);
550+
551+
// Click the editor space and send a few key presses
552+
const editor = screen.getByRole(`textbox`);
553+
await user.click(editor);
554+
await user.keyboard(" not italic");
555+
556+
// expect the edited value to be visible
557+
expect(screen.getByText("Sample text not italic")).toBeInTheDocument();
558+
await user.tripleClick(editor);
559+
const commandKey =
560+
navigator.userAgent.indexOf("Mac") !== -1 ? "Meta" : "Control";
561+
await user.keyboard(`{${commandKey}>}i{/${commandKey}>}`);
562+
563+
// expect the text to be bold
564+
expect(screen.getByText("Sample text not italic")).toHaveStyle(
565+
"font-style: italic",
566+
);
567+
await user.keyboard(`{${commandKey}>}i{/${commandKey}>}`);
568+
569+
// expect the text to be normal
570+
expect(screen.getByText("Sample text not italic")).not.toHaveStyle(
571+
"font-style: italic",
572+
);
573+
});
574+
});

0 commit comments

Comments
 (0)