Skip to content

Commit b80acee

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

File tree

6 files changed

+178
-1
lines changed

6 files changed

+178
-1
lines changed

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

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

+84
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,48 @@ 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+
463+
const textbox = await page.locator("div[role='textbox']");
464+
465+
expect(await page.locator("strong").count()).toBe(0);
466+
expect(await page.locator("span[data-lexical-text='true']").count()).toBe(
467+
1,
468+
);
469+
470+
await textbox.click();
471+
472+
const boldButton = await page.locator(
473+
"button[data-role='pw-rte-bold-button']",
474+
);
475+
476+
await boldButton.click();
477+
await textbox.click();
478+
await textbox.pressSequentially("This is some bold text");
479+
480+
expect(await page.locator("strong").count()).toBe(1);
481+
await page.locator("text=This is some bold text").evaluate((el) => {
482+
const style = window.getComputedStyle(el);
483+
return Number(style.fontWeight) >= 700;
484+
});
485+
486+
await boldButton.click();
487+
await textbox.click();
488+
await textbox.pressSequentially(" and this is not");
489+
490+
expect(await page.locator("span[data-lexical-text='true']").count()).toBe(
491+
2,
492+
);
493+
await page.locator("text=and this is not").evaluate((el) => {
494+
const style = window.getComputedStyle(el);
495+
return Number(style.fontWeight) < 700;
496+
});
497+
});
456498
});
457499

458500
test.describe("Italic", () => {
@@ -473,6 +515,48 @@ test.describe("Functionality tests", () => {
473515
await italicButton.click();
474516
expect(await page.locator("em").count()).toBe(0);
475517
});
518+
519+
test("applies and removes italic formatting to the editor directly", async ({
520+
mount,
521+
page,
522+
}) => {
523+
await mount(<TextEditorDefaultComponent value={unformattedValue} />);
524+
525+
const textbox = await page.locator("div[role='textbox']");
526+
527+
expect(await page.locator("em").count()).toBe(0);
528+
expect(await page.locator("span[data-lexical-text='true']").count()).toBe(
529+
1,
530+
);
531+
532+
await textbox.click();
533+
534+
const italicButton = await page.locator(
535+
"button[data-role='pw-rte-italic-button']",
536+
);
537+
538+
await italicButton.click();
539+
await textbox.click();
540+
await textbox.pressSequentially("This is some italic text");
541+
542+
expect(await page.locator("em").count()).toBe(1);
543+
await page.locator("text=This is some italic text").evaluate((el) => {
544+
const style = window.getComputedStyle(el);
545+
return style.fontStyle === "italic";
546+
});
547+
548+
await italicButton.click();
549+
await textbox.click();
550+
await textbox.pressSequentially(" and this is not");
551+
552+
expect(await page.locator("span[data-lexical-text='true']").count()).toBe(
553+
2,
554+
);
555+
await page.locator("text=and this is not").evaluate((el) => {
556+
const style = window.getComputedStyle(el);
557+
return style.fontStyle === "italic";
558+
});
559+
});
476560
});
477561

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

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

+80
Original file line numberDiff line numberDiff line change
@@ -488,3 +488,83 @@ 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+
await user.keyboard(`{Control>}b{/Control>}`);
519+
520+
// expect the text to be bold
521+
expect(screen.getByText("Sample text not bold")).toHaveStyle(
522+
"font-weight: bold",
523+
);
524+
await user.keyboard(`{Control>}b{/Control>}`);
525+
526+
// expect the text to be normal
527+
expect(screen.getByText("Sample text not bold")).not.toHaveStyle(
528+
"font-weight: bold",
529+
);
530+
});
531+
532+
it("should toggle italic text when the italic shortcut is pressed", async () => {
533+
const user = userEvent.setup();
534+
const mockCancel = jest.fn();
535+
const mockSave = jest.fn();
536+
const value = JSON.stringify(initialValue);
537+
538+
// render the TextEditor component
539+
render(
540+
<TextEditor
541+
labelText="Example"
542+
onCancel={() => mockCancel()}
543+
onSave={() => mockSave()}
544+
value={value}
545+
characterLimit={20}
546+
/>,
547+
);
548+
549+
// Click the editor space and send a few key presses
550+
const editor = screen.getByRole(`textbox`);
551+
await user.click(editor);
552+
await user.keyboard(" not italic");
553+
554+
// expect the edited value to be visible
555+
expect(screen.getByText("Sample text not italic")).toBeInTheDocument();
556+
await user.tripleClick(editor);
557+
await user.keyboard(`{Control>}i{/Control>}`);
558+
559+
// expect the text to be bold
560+
expect(screen.getByText("Sample text not italic")).toHaveStyle(
561+
"font-style: italic",
562+
);
563+
await user.keyboard(`{Control>}i{/Control>}`);
564+
565+
// expect the text to be normal
566+
expect(screen.getByText("Sample text not italic")).not.toHaveStyle(
567+
"font-style: italic",
568+
);
569+
});
570+
});

0 commit comments

Comments
 (0)