@squiz/formatted-text-editor 1.12.0-alpha.44 → 1.12.0-alpha.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/EditorToolbar/EditorToolbar.js +1 -1
- package/lib/EditorToolbar/Tools/Link/Form/LinkForm.js +5 -5
- package/lib/EditorToolbar/Tools/TextType/Heading/HeadingButton.js +1 -1
- package/lib/EditorToolbar/Tools/TextType/Paragraph/ParagraphButton.js +2 -3
- package/lib/EditorToolbar/Tools/TextType/Preformatted/PreformattedButton.js +1 -1
- package/lib/FormattedTextEditor.js +3 -2
- package/lib/index.css +161 -459
- package/lib/ui/Inputs/Select/Select.js +1 -1
- package/lib/ui/Inputs/Text/TextInput.js +2 -2
- package/lib/ui/Modal/Modal.js +7 -7
- package/lib/ui/ToolbarButton/ToolbarButton.js +1 -1
- package/lib/ui/ToolbarDropdown/ToolbarDropdown.d.ts +0 -1
- package/lib/ui/ToolbarDropdown/ToolbarDropdown.js +14 -6
- package/lib/ui/{DropdownButton/DropdownButton.js → ToolbarDropdownButton/ToolbarDropdownButton.js} +1 -1
- package/package.json +4 -4
- package/postcss.config.js +9 -1
- package/src/Editor/_editor.scss +1 -1
- package/src/EditorToolbar/EditorToolbar.tsx +1 -1
- package/src/EditorToolbar/Tools/Bold/BoldButton.spec.tsx +1 -1
- package/src/EditorToolbar/Tools/Italic/ItalicButton.spec.tsx +1 -1
- package/src/EditorToolbar/Tools/Link/Form/LinkForm.spec.tsx +1 -1
- package/src/EditorToolbar/Tools/Link/Form/LinkForm.tsx +5 -5
- package/src/EditorToolbar/Tools/TextAlign/CenterAlign/CenterAlignButton.spec.tsx +39 -0
- package/src/EditorToolbar/Tools/TextAlign/JustifyAlign/JustifyAlignButton.spec.tsx +39 -0
- package/src/EditorToolbar/Tools/TextAlign/LeftAlign/LeftAlignButton.spec.tsx +39 -0
- package/src/EditorToolbar/Tools/TextAlign/RightAlign/RightAlignButton.spec.tsx +39 -0
- package/src/EditorToolbar/Tools/TextType/Heading/HeadingButton.spec.tsx +56 -0
- package/src/EditorToolbar/Tools/TextType/Heading/HeadingButton.tsx +1 -1
- package/src/EditorToolbar/Tools/TextType/Paragraph/ParagraphButton.spec.tsx +30 -0
- package/src/EditorToolbar/Tools/TextType/Paragraph/ParagraphButton.tsx +2 -3
- package/src/EditorToolbar/Tools/TextType/Preformatted/PreformattedButton.spec.tsx +47 -0
- package/src/EditorToolbar/Tools/TextType/Preformatted/PreformattedButton.tsx +1 -1
- package/src/EditorToolbar/Tools/TextType/TextTypeDropdown.spec.tsx +51 -0
- package/src/EditorToolbar/Tools/Underline/Underline.spec.tsx +1 -1
- package/src/EditorToolbar/_editor-toolbar.scss +4 -2
- package/src/FormattedTextEditor.tsx +4 -2
- package/src/index.scss +2 -2
- package/src/ui/Inputs/Select/Select.tsx +1 -1
- package/src/ui/Inputs/Text/TextInput.tsx +2 -2
- package/src/ui/Modal/Modal.tsx +7 -7
- package/src/ui/Modal/_modal.scss +2 -2
- package/src/ui/ToolbarButton/ToolbarButton.tsx +1 -1
- package/src/ui/ToolbarDropdown/ToolbarDropdown.spec.tsx +78 -0
- package/src/ui/ToolbarDropdown/ToolbarDropdown.tsx +22 -12
- package/src/ui/ToolbarDropdown/_toolbar-dropdown.scss +25 -20
- package/src/ui/ToolbarDropdownButton/ToolbarDropdownButton.spec.tsx +48 -0
- package/src/ui/{DropdownButton/DropdownButton.tsx → ToolbarDropdownButton/ToolbarDropdownButton.tsx} +1 -0
- package/src/ui/{DropdownButton/_dropdown-button.scss → ToolbarDropdownButton/_toolbar-dropdown-button.scss} +7 -1
- package/src/ui/_buttons.scss +1 -1
- package/src/ui/_forms.scss +1 -1
- package/tailwind.config.cjs +2 -4
- /package/lib/ui/{DropdownButton/DropdownButton.d.ts → ToolbarDropdownButton/ToolbarDropdownButton.d.ts} +0 -0
@@ -6,7 +6,7 @@ import clsx from 'clsx';
|
|
6
6
|
export const Select = ({ id, label, value, options }) => {
|
7
7
|
const [selectedOption, setSelectedOption] = useState(value);
|
8
8
|
return (React.createElement(React.Fragment, null,
|
9
|
-
label && (React.createElement("label", { htmlFor: id, className: "
|
9
|
+
label && (React.createElement("label", { htmlFor: id, className: "squiz-fte-form-label" }, label)),
|
10
10
|
React.createElement("div", { className: "relative text-md text-gray-800" },
|
11
11
|
React.createElement(Listbox, { value: selectedOption, onChange: setSelectedOption, name: id, "aria-labelledby": id }, ({ open }) => (React.createElement(React.Fragment, null,
|
12
12
|
React.createElement(Listbox.Label, { className: "sr-only" }, label),
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
export const TextInput = ({ id, label, value, ...rest }) => {
|
3
3
|
return (React.createElement(React.Fragment, null,
|
4
|
-
label && (React.createElement("label", { htmlFor: id, className: "
|
5
|
-
React.createElement("input", { name: id, id: id, type: "text", className: "
|
4
|
+
label && (React.createElement("label", { htmlFor: id, className: "squiz-fte-form-label" }, label)),
|
5
|
+
React.createElement("input", { name: id, id: id, type: "text", className: "squiz-fte-form-control", defaultValue: value, ...rest })));
|
6
6
|
};
|
package/lib/ui/Modal/Modal.js
CHANGED
@@ -14,17 +14,17 @@ const Modal = ({ children, onCancel, onSubmit, className }) => {
|
|
14
14
|
return () => window.removeEventListener('keydown', keydown);
|
15
15
|
}, []);
|
16
16
|
return (React.createElement(React.Fragment, null,
|
17
|
-
React.createElement("div", { className: `
|
17
|
+
React.createElement("div", { className: `squiz-fte-modal-wrapper ${className ? className : ''}` },
|
18
18
|
React.createElement("div", { className: "w-modal-sm my-6 mx-auto" },
|
19
|
-
React.createElement("div", { className: "
|
20
|
-
React.createElement("div", { className: "
|
19
|
+
React.createElement("div", { className: "squiz-fte-modal" },
|
20
|
+
React.createElement("div", { className: "squiz-fte-modal-header p-6 pb-2" },
|
21
21
|
React.createElement("h2", { className: "font-semibold text-gray-900 text-heading-2" }, "Link"),
|
22
22
|
React.createElement("button", { className: "ml-auto -mr-3 -mt-3 bg-transparent border-0 text-gray-600 font-semibold outline-none focus:outline-none hover:text-color-gray-800", onClick: onCancel, "aria-label": "Close" },
|
23
23
|
React.createElement(CloseRoundedIcon, null))),
|
24
|
-
React.createElement("div", { className: "
|
25
|
-
React.createElement("div", { className: "
|
26
|
-
React.createElement("button", { className: "
|
27
|
-
onSubmit && (React.createElement("button", { className: "
|
24
|
+
React.createElement("div", { className: "squiz-fte-modal-content" }, children),
|
25
|
+
React.createElement("div", { className: "squiz-fte-modal-footer p-6 pt-3" },
|
26
|
+
React.createElement("button", { className: "squiz-fte-modal-footer__button bg-gray-200 text-gray-700 mr-2 hover:bg-gray-300", type: "button", onClick: onCancel, "aria-label": "Cancel" }, "Cancel"),
|
27
|
+
onSubmit && (React.createElement("button", { className: "squiz-fte-modal-footer__button bg-blue-300 text-white hover:bg-blue-400", type: "button", onClick: onSubmit, "aria-label": "Apply" }, "Apply")))))),
|
28
28
|
React.createElement("div", { className: "opacity-25 fixed inset-0 z-40 bg-black" })));
|
29
29
|
};
|
30
30
|
export default Modal;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
const ToolbarButton = ({ handleOnClick, isDisabled, isActive, icon, label }) => {
|
3
|
-
return (React.createElement("button", { "aria-label": label, title: label, type: "button", onClick: handleOnClick, disabled: isDisabled, className: `
|
3
|
+
return (React.createElement("button", { "aria-label": label, title: label, type: "button", onClick: handleOnClick, disabled: isDisabled, className: `squiz-fte-btn toolbar-button ${isActive ? 'is-active' : ''}` }, icon));
|
4
4
|
};
|
5
5
|
export default ToolbarButton;
|
@@ -1,12 +1,20 @@
|
|
1
|
-
import React from 'react';
|
1
|
+
import React, { useState } from 'react';
|
2
2
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
3
|
-
import 'flowbite';
|
4
3
|
const ToolbarDropdown = ({ children, label }) => {
|
5
|
-
|
6
|
-
|
4
|
+
const [isOpen, setOpen] = useState(false);
|
5
|
+
const handleDropDown = () => {
|
6
|
+
setOpen(!isOpen);
|
7
|
+
};
|
8
|
+
const handleBlur = (event) => {
|
9
|
+
if (event.relatedTarget?.id !== 'dropdownMenuButton' && !event.target?.className.includes('is-active')) {
|
10
|
+
isOpen && handleDropDown();
|
11
|
+
}
|
12
|
+
};
|
13
|
+
return (React.createElement("div", { className: "toolbar-dropdown", onBlur: handleBlur },
|
14
|
+
React.createElement("button", { id: "dropdownHoverButton", className: "toolbar-dropdown__button", onClick: handleDropDown },
|
7
15
|
React.createElement("span", { className: "toolbar-dropdown__label" }, label),
|
8
16
|
React.createElement(ExpandMoreIcon, { className: "toolbar-dropdown__icon", "aria-hidden": "true" })),
|
9
|
-
React.createElement("div", { id: "dropdown", className:
|
10
|
-
React.createElement("ul", { "aria-labelledby": "dropdownHoverButton" }, children))));
|
17
|
+
React.createElement("div", { id: "dropdown", className: `toolbar-dropdown__menu z-10 ${isOpen ? 'block' : 'hidden'} bg-white divide-y w-169` },
|
18
|
+
React.createElement("ul", { "aria-labelledby": "dropdownHoverButton", onClick: handleDropDown }, children))));
|
11
19
|
};
|
12
20
|
export default ToolbarDropdown;
|
package/lib/ui/{DropdownButton/DropdownButton.js → ToolbarDropdownButton/ToolbarDropdownButton.js}
RENAMED
@@ -1,7 +1,7 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import CheckIcon from '@mui/icons-material/Check';
|
3
3
|
const DropdownButton = ({ children, handleOnClick, isDisabled, isActive, label }) => {
|
4
|
-
return (React.createElement("button", { "aria-label": label, title: label, type: "button", onClick: handleOnClick, disabled: isDisabled, className: `btn dropdown-button ${isActive ? 'is-active' : ''}` },
|
4
|
+
return (React.createElement("button", { "aria-label": label, id: "dropdownMenuButton", title: label, type: "button", onClick: handleOnClick, disabled: isDisabled, className: `btn dropdown-button ${isActive ? 'is-active' : ''}` },
|
5
5
|
React.createElement("span", null, children || label),
|
6
6
|
isActive && React.createElement(CheckIcon, { className: "dropdown-button-icon" })));
|
7
7
|
};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@squiz/formatted-text-editor",
|
3
|
-
"version": "1.12.0-alpha.
|
3
|
+
"version": "1.12.0-alpha.46",
|
4
4
|
"main": "lib/index.js",
|
5
5
|
"types": "lib/index.d.ts",
|
6
6
|
"scripts": {
|
@@ -19,8 +19,8 @@
|
|
19
19
|
"@headlessui/react": "1.7.11",
|
20
20
|
"@mui/icons-material": "5.11.0",
|
21
21
|
"@remirror/react": "2.0.25",
|
22
|
-
"clsx": "
|
23
|
-
"
|
22
|
+
"clsx": "1.2.1",
|
23
|
+
"postcss-prefix-selector": "1.16.0"
|
24
24
|
},
|
25
25
|
"devDependencies": {
|
26
26
|
"@testing-library/cypress": "9.0.0",
|
@@ -64,5 +64,5 @@
|
|
64
64
|
"volta": {
|
65
65
|
"node": "16.19.0"
|
66
66
|
},
|
67
|
-
"gitHead": "
|
67
|
+
"gitHead": "047173c3a5a8d33be8d9becf6af6d5575d7ce914"
|
68
68
|
}
|
package/postcss.config.js
CHANGED
@@ -1,3 +1,11 @@
|
|
1
1
|
module.exports = {
|
2
|
-
plugins: [
|
2
|
+
plugins: [
|
3
|
+
require('tailwindcss'),
|
4
|
+
require('autoprefixer'),
|
5
|
+
require('postcss-nested'),
|
6
|
+
require('postcss-prefix-selector')({
|
7
|
+
prefix: '.squiz-fte-scope',
|
8
|
+
exclude: ['.squiz-fte-scope__floating-popover'],
|
9
|
+
}),
|
10
|
+
],
|
3
11
|
};
|
package/src/Editor/_editor.scss
CHANGED
@@ -42,7 +42,7 @@ export const EditorToolbar = ({ manager, isPopover }: EditorToolbarProps) => {
|
|
42
42
|
<TriggerLinkModal />
|
43
43
|
</Toolbar>
|
44
44
|
) : (
|
45
|
-
<FloatingToolbar className="
|
45
|
+
<FloatingToolbar className="squiz-fte-scope squiz-fte-scope__floating-popover">
|
46
46
|
{extensionNames.bold && <BoldButton />}
|
47
47
|
{extensionNames.italic && <ItalicButton />}
|
48
48
|
{extensionNames.underline && <UnderlineButton />}
|
@@ -11,7 +11,7 @@ describe('Bold button', () => {
|
|
11
11
|
|
12
12
|
it('Activates the button if clicked', () => {
|
13
13
|
render(<Editor />);
|
14
|
-
expect(screen.getByRole('button', { name: 'Bold (cmd+B)' }).classList.contains('
|
14
|
+
expect(screen.getByRole('button', { name: 'Bold (cmd+B)' }).classList.contains('squiz-fte-btn')).toBeTruthy();
|
15
15
|
const bold = screen.getByRole('button', { name: 'Bold (cmd+B)' });
|
16
16
|
fireEvent.click(bold);
|
17
17
|
expect(bold.classList.contains('is-active')).toBeTruthy();
|
@@ -11,7 +11,7 @@ describe('Italic button', () => {
|
|
11
11
|
|
12
12
|
it('Activates the button if clicked', () => {
|
13
13
|
render(<Editor />);
|
14
|
-
expect(screen.getByRole('button', { name: 'Italic (cmd+I)' }).classList.contains('
|
14
|
+
expect(screen.getByRole('button', { name: 'Italic (cmd+I)' }).classList.contains('squiz-fte-btn')).toBeTruthy();
|
15
15
|
const italic = screen.getByRole('button', { name: 'Italic (cmd+I)' });
|
16
16
|
fireEvent.click(italic);
|
17
17
|
expect(italic.classList.contains('is-active')).toBeTruthy();
|
@@ -15,7 +15,7 @@ describe('Link Form', () => {
|
|
15
15
|
it('Renders the form with the specified class', () => {
|
16
16
|
render(<LinkForm />);
|
17
17
|
|
18
|
-
const formClass = document.querySelector('.
|
18
|
+
const formClass = document.querySelector('.squiz-fte-form');
|
19
19
|
expect(formClass).toBeInTheDocument();
|
20
20
|
});
|
21
21
|
});
|
@@ -21,17 +21,17 @@ const LinkForm = (): ReactElement => {
|
|
21
21
|
};
|
22
22
|
|
23
23
|
return (
|
24
|
-
<form action="" method="post" className="
|
25
|
-
<div className="
|
24
|
+
<form action="" method="post" className="squiz-fte-form">
|
25
|
+
<div className="squiz-fte-form-group mb-2">
|
26
26
|
<TextInput id="href" label="URL" value={formValues.href} onChange={handleChange} />
|
27
27
|
</div>
|
28
|
-
<div className="
|
28
|
+
<div className="squiz-fte-form-group mb-2">
|
29
29
|
<TextInput id="text" label="Text" value={formValues.text} onChange={handleChange} />
|
30
30
|
</div>
|
31
|
-
<div className="
|
31
|
+
<div className="squiz-fte-form-group mb-2">
|
32
32
|
<TextInput id="title" label="Title" value={formValues.title} onChange={handleChange} />
|
33
33
|
</div>
|
34
|
-
<div className="
|
34
|
+
<div className="squiz-fte-form-group mb-0">
|
35
35
|
<Select id="target" label="Target" value={formValues.target} options={selectOptions} />
|
36
36
|
</div>
|
37
37
|
</form>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import '@testing-library/jest-dom';
|
2
|
+
import { render, fireEvent } from '@testing-library/react';
|
3
|
+
import Editor from '../../../../Editor/Editor';
|
4
|
+
import React from 'react';
|
5
|
+
|
6
|
+
describe('Center align button', () => {
|
7
|
+
it('Renders the center align button', () => {
|
8
|
+
const { baseElement, getByRole } = render(<Editor />);
|
9
|
+
expect(baseElement).toBeTruthy();
|
10
|
+
expect(getByRole('button', { name: 'Align center' })).toBeTruthy();
|
11
|
+
});
|
12
|
+
|
13
|
+
it('Applies active status after selecting center align button', () => {
|
14
|
+
const { baseElement, getByRole } = render(<Editor />);
|
15
|
+
expect(baseElement).toBeTruthy();
|
16
|
+
|
17
|
+
const centerAlignButton = getByRole('button', { name: 'Align center' });
|
18
|
+
expect(centerAlignButton).toBeTruthy();
|
19
|
+
expect(centerAlignButton.classList.contains('is-active')).toBeFalsy();
|
20
|
+
|
21
|
+
fireEvent.click(centerAlignButton);
|
22
|
+
|
23
|
+
setTimeout(() => {
|
24
|
+
expect(centerAlignButton.classList.contains('is-active')).toBeTruthy();
|
25
|
+
}, 50);
|
26
|
+
});
|
27
|
+
|
28
|
+
it('Should apply center alignment to editor after clicking button', () => {
|
29
|
+
const { baseElement, getByRole } = render(<Editor />);
|
30
|
+
expect(baseElement).toBeTruthy();
|
31
|
+
expect(baseElement.querySelector('p[data-node-text-align="center"]')).toBeFalsy();
|
32
|
+
|
33
|
+
const centerAlignButton = getByRole('button', { name: 'Align center' });
|
34
|
+
expect(centerAlignButton).toBeTruthy();
|
35
|
+
fireEvent.click(centerAlignButton);
|
36
|
+
|
37
|
+
expect(baseElement.querySelector('p[data-node-text-align="center"]')).toBeTruthy();
|
38
|
+
});
|
39
|
+
});
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import '@testing-library/jest-dom';
|
2
|
+
import { render, fireEvent } from '@testing-library/react';
|
3
|
+
import Editor from '../../../../Editor/Editor';
|
4
|
+
import React from 'react';
|
5
|
+
|
6
|
+
describe('Justify align button', () => {
|
7
|
+
it('Renders the justify align button', () => {
|
8
|
+
const { baseElement, getByRole } = render(<Editor />);
|
9
|
+
expect(baseElement).toBeTruthy();
|
10
|
+
expect(getByRole('button', { name: 'Justify' })).toBeTruthy();
|
11
|
+
});
|
12
|
+
|
13
|
+
it('Applies active status after selecting justify align button', () => {
|
14
|
+
const { baseElement, getByRole } = render(<Editor />);
|
15
|
+
expect(baseElement).toBeTruthy();
|
16
|
+
|
17
|
+
const justifyAlignButton = getByRole('button', { name: 'Justify' });
|
18
|
+
expect(justifyAlignButton).toBeTruthy();
|
19
|
+
expect(justifyAlignButton.classList.contains('is-active')).toBeFalsy();
|
20
|
+
|
21
|
+
fireEvent.click(justifyAlignButton);
|
22
|
+
|
23
|
+
setTimeout(() => {
|
24
|
+
expect(justifyAlignButton.classList.contains('is-active')).toBeTruthy();
|
25
|
+
}, 50);
|
26
|
+
});
|
27
|
+
|
28
|
+
it('Should apply justify alignment to editor after clicking button', () => {
|
29
|
+
const { baseElement, getByRole } = render(<Editor />);
|
30
|
+
expect(baseElement).toBeTruthy();
|
31
|
+
expect(baseElement.querySelector('p[data-node-text-align="justify"]')).toBeFalsy();
|
32
|
+
|
33
|
+
const justifyAlignButton = getByRole('button', { name: 'Justify' });
|
34
|
+
expect(justifyAlignButton).toBeTruthy();
|
35
|
+
fireEvent.click(justifyAlignButton);
|
36
|
+
|
37
|
+
expect(baseElement.querySelector('p[data-node-text-align="justify"]')).toBeTruthy();
|
38
|
+
});
|
39
|
+
});
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import '@testing-library/jest-dom';
|
2
|
+
import { render, fireEvent } from '@testing-library/react';
|
3
|
+
import Editor from '../../../../Editor/Editor';
|
4
|
+
import React from 'react';
|
5
|
+
|
6
|
+
describe('Left align button', () => {
|
7
|
+
it('Renders the left align button', () => {
|
8
|
+
const { baseElement, getByRole } = render(<Editor />);
|
9
|
+
expect(baseElement).toBeTruthy();
|
10
|
+
expect(getByRole('button', { name: 'Align left' })).toBeTruthy();
|
11
|
+
});
|
12
|
+
|
13
|
+
it('Applies active status after selecting left align button', () => {
|
14
|
+
const { baseElement, getByRole } = render(<Editor />);
|
15
|
+
expect(baseElement).toBeTruthy();
|
16
|
+
|
17
|
+
const leftAlignButton = getByRole('button', { name: 'Align left' });
|
18
|
+
expect(leftAlignButton).toBeTruthy();
|
19
|
+
expect(leftAlignButton.classList.contains('is-active')).toBeFalsy();
|
20
|
+
|
21
|
+
fireEvent.click(leftAlignButton);
|
22
|
+
|
23
|
+
setTimeout(() => {
|
24
|
+
expect(leftAlignButton.classList.contains('is-active')).toBeTruthy();
|
25
|
+
}, 50);
|
26
|
+
});
|
27
|
+
|
28
|
+
it('Should apply left alignment to editor after clicking button', () => {
|
29
|
+
const { baseElement, getByRole } = render(<Editor />);
|
30
|
+
expect(baseElement).toBeTruthy();
|
31
|
+
expect(baseElement.querySelector('p[data-node-text-align="left"]')).toBeFalsy();
|
32
|
+
|
33
|
+
const leftAlignButton = getByRole('button', { name: 'Align left' });
|
34
|
+
expect(leftAlignButton).toBeTruthy();
|
35
|
+
fireEvent.click(leftAlignButton);
|
36
|
+
|
37
|
+
expect(baseElement.querySelector('p[data-node-text-align="left"]')).toBeTruthy();
|
38
|
+
});
|
39
|
+
});
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import '@testing-library/jest-dom';
|
2
|
+
import { render, fireEvent } from '@testing-library/react';
|
3
|
+
import Editor from '../../../../Editor/Editor';
|
4
|
+
import React from 'react';
|
5
|
+
|
6
|
+
describe('Right align button', () => {
|
7
|
+
it('Renders the right align button', () => {
|
8
|
+
const { baseElement, getByRole } = render(<Editor />);
|
9
|
+
expect(baseElement).toBeTruthy();
|
10
|
+
expect(getByRole('button', { name: 'Align right' })).toBeTruthy();
|
11
|
+
});
|
12
|
+
|
13
|
+
it('Applies active status after selecting right align button', () => {
|
14
|
+
const { baseElement, getByRole } = render(<Editor />);
|
15
|
+
expect(baseElement).toBeTruthy();
|
16
|
+
|
17
|
+
const rightAlignButton = getByRole('button', { name: 'Align right' });
|
18
|
+
expect(rightAlignButton).toBeTruthy();
|
19
|
+
expect(rightAlignButton.classList.contains('is-active')).toBeFalsy();
|
20
|
+
|
21
|
+
fireEvent.click(rightAlignButton);
|
22
|
+
|
23
|
+
setTimeout(() => {
|
24
|
+
expect(rightAlignButton.classList.contains('is-active')).toBeTruthy();
|
25
|
+
}, 50);
|
26
|
+
});
|
27
|
+
|
28
|
+
it('Should apply right alignment to editor after clicking button', () => {
|
29
|
+
const { baseElement, getByRole } = render(<Editor />);
|
30
|
+
expect(baseElement).toBeTruthy();
|
31
|
+
expect(baseElement.querySelector('p[data-node-text-align="right"]')).toBeFalsy();
|
32
|
+
|
33
|
+
const rightAlignButton = getByRole('button', { name: 'Align right' });
|
34
|
+
expect(rightAlignButton).toBeTruthy();
|
35
|
+
fireEvent.click(rightAlignButton);
|
36
|
+
|
37
|
+
expect(baseElement.querySelector('p[data-node-text-align="right"]')).toBeTruthy();
|
38
|
+
});
|
39
|
+
});
|
@@ -0,0 +1,56 @@
|
|
1
|
+
import '@testing-library/jest-dom';
|
2
|
+
import { render, fireEvent } from '@testing-library/react';
|
3
|
+
import Editor from '../../../../Editor/Editor';
|
4
|
+
import React from 'react';
|
5
|
+
|
6
|
+
const headings = [
|
7
|
+
['Heading 1', 'h1'],
|
8
|
+
['Heading 2', 'h2'],
|
9
|
+
['Heading 3', 'h3'],
|
10
|
+
['Heading 4', 'h4'],
|
11
|
+
['Heading 5', 'h5'],
|
12
|
+
['Heading 6', 'h6'],
|
13
|
+
];
|
14
|
+
|
15
|
+
describe('Heading button', () => {
|
16
|
+
it.each(headings)('Renders the "%s" heading button', (label) => {
|
17
|
+
const { baseElement, getByRole } = render(<Editor />);
|
18
|
+
expect(baseElement).toBeTruthy();
|
19
|
+
expect(getByRole('button', { name: label })).toBeTruthy();
|
20
|
+
});
|
21
|
+
|
22
|
+
it.each(headings)('Applies active status after selecting "%s" heading button', (label) => {
|
23
|
+
const { baseElement, getByRole } = render(<Editor />);
|
24
|
+
expect(baseElement).toBeTruthy();
|
25
|
+
|
26
|
+
const headingButton = getByRole('button', { name: label });
|
27
|
+
expect(headingButton).toBeTruthy();
|
28
|
+
expect(headingButton.className).not.toContain('is-active');
|
29
|
+
|
30
|
+
fireEvent.click(headingButton);
|
31
|
+
expect(headingButton.className).toContain('is-active');
|
32
|
+
});
|
33
|
+
|
34
|
+
it.each(headings)('Should render a check icon if button is active', (label) => {
|
35
|
+
const { baseElement, getByRole } = render(<Editor />);
|
36
|
+
expect(baseElement).toBeTruthy();
|
37
|
+
|
38
|
+
const headingButton = getByRole('button', { name: label });
|
39
|
+
expect(headingButton.querySelector('svg[data-testid="CheckIcon"]')).toBeFalsy();
|
40
|
+
|
41
|
+
fireEvent.click(headingButton);
|
42
|
+
expect(headingButton.querySelector('svg[data-testid="CheckIcon"]')).toBeTruthy();
|
43
|
+
});
|
44
|
+
|
45
|
+
it.each(headings)('Should apply "%s" heading tag to editor after clicking button', (label, tag) => {
|
46
|
+
const { baseElement } = render(<Editor />);
|
47
|
+
expect(baseElement).toBeTruthy();
|
48
|
+
expect(baseElement.querySelector('div.remirror-editor h1')).toBeFalsy();
|
49
|
+
|
50
|
+
const headingButton = baseElement.querySelector(`button[title="${label}"]`) as HTMLButtonElement;
|
51
|
+
expect(headingButton).toBeTruthy();
|
52
|
+
fireEvent.click(headingButton);
|
53
|
+
|
54
|
+
expect(baseElement.querySelector(`div.remirror-editor ${tag}`)).toBeTruthy();
|
55
|
+
});
|
56
|
+
});
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import { useCommands, useChainedCommands, useActive } from '@remirror/react';
|
3
3
|
import { HeadingExtension } from '@remirror/extension-heading';
|
4
|
-
import DropdownButton from '../../../../ui/
|
4
|
+
import DropdownButton from '../../../../ui/ToolbarDropdownButton/ToolbarDropdownButton';
|
5
5
|
|
6
6
|
type HeadingButtonProps = {
|
7
7
|
level: number;
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import '@testing-library/jest-dom';
|
2
|
+
import { render } from '@testing-library/react';
|
3
|
+
import Editor from '../../../../Editor/Editor';
|
4
|
+
import React from 'react';
|
5
|
+
|
6
|
+
describe('Paragraph button', () => {
|
7
|
+
it('Renders paragraph button', () => {
|
8
|
+
const { baseElement } = render(<Editor />);
|
9
|
+
expect(baseElement).toBeTruthy();
|
10
|
+
expect(baseElement.querySelector('button[title="Paragraph"]')).toBeTruthy();
|
11
|
+
});
|
12
|
+
|
13
|
+
it('Paragraph button active status should be set on as default', () => {
|
14
|
+
const { baseElement } = render(<Editor />);
|
15
|
+
expect(baseElement).toBeTruthy();
|
16
|
+
|
17
|
+
const paragraphButton = baseElement.querySelector('button[title="Paragraph"]') as HTMLButtonElement;
|
18
|
+
expect(paragraphButton).toBeTruthy();
|
19
|
+
expect(paragraphButton.className).toContain('is-active');
|
20
|
+
});
|
21
|
+
|
22
|
+
it('Should render a check icon if button is active', () => {
|
23
|
+
const { baseElement } = render(<Editor />);
|
24
|
+
expect(baseElement).toBeTruthy();
|
25
|
+
|
26
|
+
const paragraphButton = baseElement.querySelector('button[title="Paragraph"]') as HTMLButtonElement;
|
27
|
+
expect(paragraphButton).toBeTruthy();
|
28
|
+
expect(paragraphButton.querySelector('svg[data-testid="CheckIcon"]')).toBeTruthy();
|
29
|
+
});
|
30
|
+
});
|
@@ -1,14 +1,13 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import { useCommands, useChainedCommands, useActive } from '@remirror/react';
|
3
3
|
import { ParagraphExtension } from '@remirror/extension-paragraph';
|
4
|
-
import DropdownButton from '../../../../ui/
|
4
|
+
import DropdownButton from '../../../../ui/ToolbarDropdownButton/ToolbarDropdownButton';
|
5
5
|
|
6
6
|
const ParagraphButton = () => {
|
7
7
|
const { convertParagraph } = useCommands<ParagraphExtension>();
|
8
8
|
const chain = useChainedCommands();
|
9
9
|
|
10
10
|
const active = useActive<ParagraphExtension>();
|
11
|
-
const enabled = convertParagraph.enabled();
|
12
11
|
|
13
12
|
const handleSelect = () => {
|
14
13
|
if (convertParagraph.enabled()) {
|
@@ -17,7 +16,7 @@ const ParagraphButton = () => {
|
|
17
16
|
};
|
18
17
|
|
19
18
|
return (
|
20
|
-
<DropdownButton handleOnClick={handleSelect} isDisabled={
|
19
|
+
<DropdownButton handleOnClick={handleSelect} isDisabled={false} isActive={active.paragraph()} label="Paragraph">
|
21
20
|
<p>Paragraph</p>
|
22
21
|
</DropdownButton>
|
23
22
|
);
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import '@testing-library/jest-dom';
|
2
|
+
import { render, fireEvent } from '@testing-library/react';
|
3
|
+
import Editor from '../../../../Editor/Editor';
|
4
|
+
import React from 'react';
|
5
|
+
|
6
|
+
describe('Preformatted button', () => {
|
7
|
+
it('Renders the preformatted button', () => {
|
8
|
+
const { baseElement, getByRole } = render(<Editor />);
|
9
|
+
expect(baseElement).toBeTruthy();
|
10
|
+
expect(getByRole('button', { name: 'Preformatted' })).toBeTruthy();
|
11
|
+
});
|
12
|
+
|
13
|
+
it('Applies active status after selecting preformatted button', () => {
|
14
|
+
const { baseElement, getByRole } = render(<Editor />);
|
15
|
+
expect(baseElement).toBeTruthy();
|
16
|
+
|
17
|
+
const preformattedButton = getByRole('button', { name: 'Preformatted' });
|
18
|
+
expect(preformattedButton).toBeTruthy();
|
19
|
+
expect(preformattedButton.className).not.toContain('is-active');
|
20
|
+
|
21
|
+
fireEvent.click(preformattedButton);
|
22
|
+
expect(preformattedButton.className).toContain('is-active');
|
23
|
+
});
|
24
|
+
|
25
|
+
it('Should render a check icon if button is active', () => {
|
26
|
+
const { baseElement, getByRole } = render(<Editor />);
|
27
|
+
expect(baseElement).toBeTruthy();
|
28
|
+
|
29
|
+
const preformattedButton = getByRole('button', { name: 'Preformatted' });
|
30
|
+
expect(preformattedButton.querySelector('svg[data-testid="CheckIcon"]')).toBeFalsy();
|
31
|
+
|
32
|
+
fireEvent.click(preformattedButton);
|
33
|
+
expect(preformattedButton.querySelector('svg[data-testid="CheckIcon"]')).toBeTruthy();
|
34
|
+
});
|
35
|
+
|
36
|
+
it('Should apply preformatted tag to editor after clicking button', () => {
|
37
|
+
const { baseElement, getByRole } = render(<Editor />);
|
38
|
+
expect(baseElement).toBeTruthy();
|
39
|
+
expect(baseElement.querySelector('div.remirror-editor pre')).toBeFalsy();
|
40
|
+
|
41
|
+
const preformattedButton = getByRole('button', { name: 'Preformatted' });
|
42
|
+
expect(preformattedButton).toBeTruthy();
|
43
|
+
fireEvent.click(preformattedButton);
|
44
|
+
|
45
|
+
expect(baseElement.querySelector(`div.remirror-editor pre`)).toBeTruthy();
|
46
|
+
});
|
47
|
+
});
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import { useCommands, useActive } from '@remirror/react';
|
3
3
|
import { PreformattedExtension } from '../../../../Extensions/PreformattedExtension/PreformattedExtension';
|
4
|
-
import DropdownButton from '../../../../ui/
|
4
|
+
import DropdownButton from '../../../../ui/ToolbarDropdownButton/ToolbarDropdownButton';
|
5
5
|
|
6
6
|
const PreformattedButton = () => {
|
7
7
|
const { togglePreformatted } = useCommands<PreformattedExtension>();
|
@@ -0,0 +1,51 @@
|
|
1
|
+
import '@testing-library/jest-dom';
|
2
|
+
import { render, fireEvent } from '@testing-library/react';
|
3
|
+
import Editor from '../../../Editor/Editor';
|
4
|
+
import React from 'react';
|
5
|
+
|
6
|
+
const dropdownButtons = [
|
7
|
+
'Paragraph',
|
8
|
+
'Heading 1',
|
9
|
+
'Heading 2',
|
10
|
+
'Heading 3',
|
11
|
+
'Heading 4',
|
12
|
+
'Heading 5',
|
13
|
+
'Heading 6',
|
14
|
+
'Preformatted',
|
15
|
+
];
|
16
|
+
|
17
|
+
const navigateKeys = ['Enter', 'Space'];
|
18
|
+
|
19
|
+
describe('Text type dropdown', () => {
|
20
|
+
it('should render the text type dropdown component', () => {
|
21
|
+
const { baseElement } = render(<Editor />);
|
22
|
+
expect(baseElement).toBeTruthy();
|
23
|
+
expect(baseElement.querySelector('button#dropdownHoverButton')).toBeTruthy();
|
24
|
+
});
|
25
|
+
|
26
|
+
it.each(dropdownButtons)('should render %s button in text type dropdown', (type) => {
|
27
|
+
const { baseElement } = render(<Editor />);
|
28
|
+
expect(baseElement).toBeTruthy();
|
29
|
+
|
30
|
+
const dropdownButton = baseElement.querySelector('button#dropdownHoverButton') as HTMLButtonElement;
|
31
|
+
expect(dropdownButton).toBeTruthy();
|
32
|
+
fireEvent.click(dropdownButton);
|
33
|
+
|
34
|
+
expect(baseElement.querySelector(`button[title="${type}"]`)).toBeTruthy();
|
35
|
+
});
|
36
|
+
|
37
|
+
it.each(navigateKeys)(`should display dropdown if '%s' is pressed while component is in focus`, async (key) => {
|
38
|
+
const { baseElement } = render(<Editor />);
|
39
|
+
expect(baseElement).toBeTruthy();
|
40
|
+
|
41
|
+
const dropdownMenu = baseElement.querySelector('div.toolbar-dropdown__menu') as HTMLDivElement;
|
42
|
+
expect(dropdownMenu.className).not.toContain('block'); // Hidden
|
43
|
+
|
44
|
+
const dropdownButton = baseElement.querySelector('button#dropdownHoverButton') as HTMLButtonElement;
|
45
|
+
fireEvent.keyDown(dropdownButton, { code: key });
|
46
|
+
|
47
|
+
setTimeout(() => {
|
48
|
+
expect(dropdownMenu.className).toContain('block'); // Visible
|
49
|
+
}, 50);
|
50
|
+
});
|
51
|
+
});
|
@@ -11,7 +11,7 @@ describe('Underline button', () => {
|
|
11
11
|
|
12
12
|
it('Activates the button if clicked', () => {
|
13
13
|
render(<Editor />);
|
14
|
-
expect(screen.getByRole('button', { name: 'Underline (cmd+U)' }).classList.contains('
|
14
|
+
expect(screen.getByRole('button', { name: 'Underline (cmd+U)' }).classList.contains('squiz-fte-btn')).toBeTruthy();
|
15
15
|
const underline = screen.getByRole('button', { name: 'Underline (cmd+U)' });
|
16
16
|
fireEvent.click(underline);
|
17
17
|
expect(underline.classList.contains('is-active')).toBeTruthy();
|
@@ -11,9 +11,11 @@
|
|
11
11
|
.editor-divider {
|
12
12
|
@apply -my-1 mx-1 border;
|
13
13
|
margin-right: 2px;
|
14
|
+
height: auto;
|
14
15
|
}
|
15
16
|
}
|
16
17
|
|
17
|
-
|
18
|
-
|
18
|
+
/// This class is excluded from the scope of squiz-fte-scope as it is outside of the scoped element
|
19
|
+
.squiz-fte-scope__floating-popover {
|
20
|
+
@apply bg-white border-gray-200 p-1 shadow rounded-md border flex;
|
19
21
|
}
|