@squiz/formatted-text-editor 1.12.0-alpha.39 → 1.12.0-alpha.8
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/README.md +3 -0
- package/lib/Editor/Editor.js +2 -7
- package/lib/EditorToolbar/EditorToolbar.js +3 -10
- package/lib/EditorToolbar/Tools/TextAlign/TextAlignButtons.js +1 -4
- package/lib/index.css +93 -803
- package/package.json +8 -12
- package/.eslintrc.json +0 -34
- package/CHANGELOG.md +0 -48
- package/build.js +0 -21
- package/cypress/e2e/bold.spec.cy.ts +0 -18
- package/cypress/global.d.ts +0 -9
- package/cypress/support/commands.ts +0 -130
- package/cypress/support/e2e.ts +0 -20
- package/cypress/tsconfig.json +0 -8
- package/cypress.config.ts +0 -7
- package/demo/App.tsx +0 -12
- package/demo/index.html +0 -13
- package/demo/index.scss +0 -1
- package/demo/main.tsx +0 -10
- package/demo/public/favicon-dxp.svg +0 -3
- package/demo/vite-env.d.ts +0 -1
- package/file-transformer.js +0 -1
- package/jest.config.ts +0 -27
- package/lib/EditorToolbar/Tools/Redo/RedoButton.d.ts +0 -2
- package/lib/EditorToolbar/Tools/Redo/RedoButton.js +0 -16
- package/lib/EditorToolbar/Tools/TextType/Heading/HeadingButton.d.ts +0 -5
- package/lib/EditorToolbar/Tools/TextType/Heading/HeadingButton.js +0 -32
- package/lib/EditorToolbar/Tools/TextType/Paragraph/ParagraphButton.d.ts +0 -2
- package/lib/EditorToolbar/Tools/TextType/Paragraph/ParagraphButton.js +0 -17
- package/lib/EditorToolbar/Tools/TextType/Preformatted/PreformattedButton.d.ts +0 -2
- package/lib/EditorToolbar/Tools/TextType/Preformatted/PreformattedButton.js +0 -16
- package/lib/EditorToolbar/Tools/TextType/TextTypeDropdown.d.ts +0 -2
- package/lib/EditorToolbar/Tools/TextType/TextTypeDropdown.js +0 -35
- package/lib/EditorToolbar/Tools/Undo/UndoButton.d.ts +0 -2
- package/lib/EditorToolbar/Tools/Undo/UndoButton.js +0 -16
- package/lib/extensions/PreformattedExtension/PreformattedExtension.d.ts +0 -10
- package/lib/extensions/PreformattedExtension/PreformattedExtension.js +0 -46
- package/lib/ui/DropdownButton/DropdownButton.d.ts +0 -9
- package/lib/ui/DropdownButton/DropdownButton.js +0 -8
- package/lib/ui/ToolbarDropdown/ToolbarDropdown.d.ts +0 -7
- package/lib/ui/ToolbarDropdown/ToolbarDropdown.js +0 -12
- package/postcss.config.js +0 -3
- package/src/Editor/Editor.spec.tsx +0 -228
- package/src/Editor/Editor.tsx +0 -52
- package/src/Editor/_editor.scss +0 -75
- package/src/EditorToolbar/EditorToolbar.tsx +0 -51
- package/src/EditorToolbar/Tools/Bold/BoldButton.spec.tsx +0 -19
- package/src/EditorToolbar/Tools/Bold/BoldButton.tsx +0 -30
- package/src/EditorToolbar/Tools/Italic/ItalicButton.spec.tsx +0 -19
- package/src/EditorToolbar/Tools/Italic/ItalicButton.tsx +0 -30
- package/src/EditorToolbar/Tools/Redo/RedoButton.spec.tsx +0 -59
- package/src/EditorToolbar/Tools/Redo/RedoButton.tsx +0 -30
- package/src/EditorToolbar/Tools/TextAlign/CenterAlign/CenterAlignButton.tsx +0 -31
- package/src/EditorToolbar/Tools/TextAlign/JustifyAlign/JustifyAlignButton.tsx +0 -31
- package/src/EditorToolbar/Tools/TextAlign/LeftAlign/LeftAlignButton.tsx +0 -31
- package/src/EditorToolbar/Tools/TextAlign/RightAlign/RightAlignButton.tsx +0 -31
- package/src/EditorToolbar/Tools/TextAlign/TextAlignButtons.tsx +0 -21
- package/src/EditorToolbar/Tools/TextType/Heading/HeadingButton.tsx +0 -52
- package/src/EditorToolbar/Tools/TextType/Paragraph/ParagraphButton.tsx +0 -26
- package/src/EditorToolbar/Tools/TextType/Preformatted/PreformattedButton.tsx +0 -30
- package/src/EditorToolbar/Tools/TextType/TextTypeDropdown.tsx +0 -44
- package/src/EditorToolbar/Tools/Underline/Underline.spec.tsx +0 -19
- package/src/EditorToolbar/Tools/Underline/UnderlineButton.tsx +0 -30
- package/src/EditorToolbar/Tools/Undo/UndoButton.spec.tsx +0 -49
- package/src/EditorToolbar/Tools/Undo/UndoButton.tsx +0 -30
- package/src/EditorToolbar/_editor-toolbar.scss +0 -19
- package/src/FormattedTextEditor.tsx +0 -12
- package/src/extensions/PreformattedExtension/PreformattedExtension.tsx +0 -50
- package/src/index.scss +0 -15
- package/src/index.ts +0 -3
- package/src/ui/DropdownButton/DropdownButton.tsx +0 -28
- package/src/ui/DropdownButton/_dropdown-button.scss +0 -7
- package/src/ui/ToolbarButton/ToolbarButton.tsx +0 -26
- package/src/ui/ToolbarButton/_toolbar-button.scss +0 -37
- package/src/ui/ToolbarDropdown/ToolbarDropdown.tsx +0 -32
- package/src/ui/ToolbarDropdown/_toolbar-dropdown.scss +0 -27
- package/tailwind.config.cjs +0 -62
- package/tsconfig.json +0 -22
- package/vite.config.ts +0 -19
@@ -1,46 +0,0 @@
|
|
1
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
4
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
6
|
-
};
|
7
|
-
import { command, extension, ExtensionTag, NodeExtension, toggleBlockItem, } from '@remirror/core';
|
8
|
-
let PreformattedExtension = class PreformattedExtension extends NodeExtension {
|
9
|
-
get name() {
|
10
|
-
return 'preformatted';
|
11
|
-
}
|
12
|
-
createTags() {
|
13
|
-
return [ExtensionTag.Block, ExtensionTag.TextBlock, ExtensionTag.FormattingNode];
|
14
|
-
}
|
15
|
-
createNodeSpec(extra, override) {
|
16
|
-
return {
|
17
|
-
content: 'inline*',
|
18
|
-
defining: true,
|
19
|
-
draggable: false,
|
20
|
-
...override,
|
21
|
-
attrs: {
|
22
|
-
...extra.defaults(),
|
23
|
-
},
|
24
|
-
parseDOM: [...(override.parseDOM ?? [])],
|
25
|
-
toDOM: (node) => {
|
26
|
-
return [`pre`, extra.dom(node), 0];
|
27
|
-
},
|
28
|
-
};
|
29
|
-
}
|
30
|
-
/**
|
31
|
-
* Toggle the <pre> for the current block.
|
32
|
-
*/
|
33
|
-
togglePreformatted() {
|
34
|
-
return toggleBlockItem({
|
35
|
-
type: this.type,
|
36
|
-
toggleType: 'paragraph',
|
37
|
-
});
|
38
|
-
}
|
39
|
-
};
|
40
|
-
__decorate([
|
41
|
-
command()
|
42
|
-
], PreformattedExtension.prototype, "togglePreformatted", null);
|
43
|
-
PreformattedExtension = __decorate([
|
44
|
-
extension({})
|
45
|
-
], PreformattedExtension);
|
46
|
-
export { PreformattedExtension };
|
@@ -1,9 +0,0 @@
|
|
1
|
-
type DropdownButtonProps = {
|
2
|
-
children?: JSX.Element;
|
3
|
-
handleOnClick: () => void;
|
4
|
-
isDisabled: boolean;
|
5
|
-
isActive: boolean;
|
6
|
-
label: string;
|
7
|
-
};
|
8
|
-
declare const DropdownButton: ({ children, handleOnClick, isDisabled, isActive, label }: DropdownButtonProps) => JSX.Element;
|
9
|
-
export default DropdownButton;
|
@@ -1,8 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import CheckIcon from '@mui/icons-material/Check';
|
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' : ''}` },
|
5
|
-
React.createElement("span", null, children || label),
|
6
|
-
isActive && React.createElement(CheckIcon, { className: "dropdown-button-icon" })));
|
7
|
-
};
|
8
|
-
export default DropdownButton;
|
@@ -1,12 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
3
|
-
import 'flowbite';
|
4
|
-
const ToolbarDropdown = ({ children, label }) => {
|
5
|
-
return (React.createElement(React.Fragment, null,
|
6
|
-
React.createElement("button", { id: "dropdownHoverButton", "data-dropdown-toggle": "dropdown", className: "toolbar-dropdown__button", type: "button" },
|
7
|
-
React.createElement("span", { className: "toolbar-dropdown__label" }, label),
|
8
|
-
React.createElement(ExpandMoreIcon, { className: "toolbar-dropdown__icon", "aria-hidden": "true" })),
|
9
|
-
React.createElement("div", { id: "dropdown", className: "toolbar-dropdown__menu z-10 hidden bg-white divide-y divide-gray-100 rounded-lg shadow w-169 dark:bg-gray-700" },
|
10
|
-
React.createElement("ul", { "aria-labelledby": "dropdownHoverButton" }, children))));
|
11
|
-
};
|
12
|
-
export default ToolbarDropdown;
|
package/postcss.config.js
DELETED
@@ -1,228 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import '@testing-library/jest-dom';
|
3
|
-
import Editor from './Editor';
|
4
|
-
import { fireEvent, render, screen } from '@testing-library/react';
|
5
|
-
|
6
|
-
describe('Formatted text editor', () => {
|
7
|
-
it('Renders the text editor', () => {
|
8
|
-
render(<Editor />);
|
9
|
-
expect(screen.getByRole('textbox')).toBeInTheDocument();
|
10
|
-
});
|
11
|
-
|
12
|
-
it('Renders the placeholder if there is no content', () => {
|
13
|
-
render(<Editor />);
|
14
|
-
expect(document.querySelector(`[data-placeholder='Write something']`)).toBeInTheDocument();
|
15
|
-
});
|
16
|
-
|
17
|
-
it('Renders the bold button', () => {
|
18
|
-
render(<Editor />);
|
19
|
-
expect(screen.getByRole('button', { name: 'Bold (cmd+B)' })).toBeInTheDocument();
|
20
|
-
});
|
21
|
-
|
22
|
-
it('Renders the italic button', () => {
|
23
|
-
render(<Editor />);
|
24
|
-
expect(screen.getByRole('button', { name: 'Italic (cmd+I)' })).toBeInTheDocument();
|
25
|
-
});
|
26
|
-
|
27
|
-
it('Renders the underline button', () => {
|
28
|
-
render(<Editor />);
|
29
|
-
expect(screen.getByRole('button', { name: 'Underline (cmd+U)' })).toBeInTheDocument();
|
30
|
-
});
|
31
|
-
|
32
|
-
it('Renders the align left button', () => {
|
33
|
-
render(<Editor />);
|
34
|
-
expect(screen.getByRole('button', { name: 'Align left' })).toBeInTheDocument();
|
35
|
-
});
|
36
|
-
|
37
|
-
it('Applies left alignment styling to text when clicked', () => {
|
38
|
-
const { baseElement } = render(<Editor />);
|
39
|
-
expect(baseElement).toBeTruthy();
|
40
|
-
|
41
|
-
expect(baseElement.querySelector('p[data-node-text-align="left"]')).toBeFalsy();
|
42
|
-
|
43
|
-
const leftAlignButton = baseElement.querySelector('button[title="Align left"]') as HTMLButtonElement;
|
44
|
-
expect(leftAlignButton).toBeTruthy();
|
45
|
-
|
46
|
-
fireEvent.click(leftAlignButton);
|
47
|
-
expect(baseElement.querySelector('p[data-node-text-align="left"]')).toBeTruthy();
|
48
|
-
});
|
49
|
-
|
50
|
-
it('Applies center alignment styling to text when clicked', () => {
|
51
|
-
const { baseElement } = render(<Editor />);
|
52
|
-
expect(baseElement).toBeTruthy();
|
53
|
-
|
54
|
-
expect(baseElement.querySelector('p[data-node-text-align="center"]')).toBeFalsy();
|
55
|
-
|
56
|
-
const centerAlignButton = baseElement.querySelector('button[title="Align center"]') as HTMLButtonElement;
|
57
|
-
expect(centerAlignButton).toBeTruthy();
|
58
|
-
|
59
|
-
fireEvent.click(centerAlignButton);
|
60
|
-
expect(baseElement.querySelector('p[data-node-text-align="center"]')).toBeTruthy();
|
61
|
-
});
|
62
|
-
|
63
|
-
it('Applies right alignment styling to text when clicked', () => {
|
64
|
-
const { baseElement } = render(<Editor />);
|
65
|
-
expect(baseElement).toBeTruthy();
|
66
|
-
|
67
|
-
expect(baseElement.querySelector('p[data-node-text-align="right"]')).toBeFalsy();
|
68
|
-
|
69
|
-
const rightAlignButton = baseElement.querySelector('button[title="Align right"]') as HTMLButtonElement;
|
70
|
-
expect(rightAlignButton).toBeTruthy();
|
71
|
-
|
72
|
-
fireEvent.click(rightAlignButton);
|
73
|
-
expect(baseElement.querySelector('p[data-node-text-align="right"]')).toBeTruthy();
|
74
|
-
});
|
75
|
-
|
76
|
-
it('Applies justify alignment styling to text when clicked', () => {
|
77
|
-
const { baseElement } = render(<Editor />);
|
78
|
-
expect(baseElement).toBeTruthy();
|
79
|
-
|
80
|
-
expect(baseElement.querySelector('p[data-node-text-align="justify"]')).toBeFalsy();
|
81
|
-
|
82
|
-
const justifyAlignButton = baseElement.querySelector('button[title="Justify"]') as HTMLButtonElement;
|
83
|
-
expect(justifyAlignButton).toBeTruthy();
|
84
|
-
|
85
|
-
fireEvent.click(justifyAlignButton);
|
86
|
-
expect(baseElement.querySelector('p[data-node-text-align="justify"]')).toBeTruthy();
|
87
|
-
});
|
88
|
-
|
89
|
-
it('Applies Heading 1 styling to text when clicked', () => {
|
90
|
-
const { baseElement } = render(<Editor />);
|
91
|
-
expect(baseElement).toBeTruthy();
|
92
|
-
|
93
|
-
expect(baseElement.querySelector('div.remirror-editor h1')).toBeFalsy();
|
94
|
-
|
95
|
-
const headingDropdown = baseElement.querySelector('.toolbar-dropdown__button') as HTMLButtonElement;
|
96
|
-
expect(headingDropdown).toBeTruthy();
|
97
|
-
fireEvent.click(headingDropdown);
|
98
|
-
|
99
|
-
const h1Button = baseElement.querySelector('button[title="Heading 1"]') as HTMLButtonElement;
|
100
|
-
expect(h1Button).toBeTruthy();
|
101
|
-
fireEvent.click(h1Button);
|
102
|
-
|
103
|
-
expect(baseElement.querySelector('div.remirror-editor h1')).toBeTruthy();
|
104
|
-
});
|
105
|
-
|
106
|
-
it('Applies Heading 2 styling to text when clicked', () => {
|
107
|
-
const { baseElement } = render(<Editor />);
|
108
|
-
expect(baseElement).toBeTruthy();
|
109
|
-
|
110
|
-
expect(baseElement.querySelector('div.remirror-editor h2')).toBeFalsy();
|
111
|
-
|
112
|
-
const headingDropdown = baseElement.querySelector('.toolbar-dropdown__button') as HTMLButtonElement;
|
113
|
-
expect(headingDropdown).toBeTruthy();
|
114
|
-
fireEvent.click(headingDropdown);
|
115
|
-
|
116
|
-
const h2Button = baseElement.querySelector('button[title="Heading 2"]') as HTMLButtonElement;
|
117
|
-
expect(h2Button).toBeTruthy();
|
118
|
-
fireEvent.click(h2Button);
|
119
|
-
|
120
|
-
expect(baseElement.querySelector('div.remirror-editor h2')).toBeTruthy();
|
121
|
-
});
|
122
|
-
|
123
|
-
it('Applies Heading 3 styling to text when clicked', () => {
|
124
|
-
const { baseElement } = render(<Editor />);
|
125
|
-
expect(baseElement).toBeTruthy();
|
126
|
-
|
127
|
-
expect(baseElement.querySelector('div.remirror-editor h3')).toBeFalsy();
|
128
|
-
|
129
|
-
const headingDropdown = baseElement.querySelector('.toolbar-dropdown__button') as HTMLButtonElement;
|
130
|
-
expect(headingDropdown).toBeTruthy();
|
131
|
-
fireEvent.click(headingDropdown);
|
132
|
-
|
133
|
-
const h3Button = baseElement.querySelector('button[title="Heading 3"]') as HTMLButtonElement;
|
134
|
-
expect(h3Button).toBeTruthy();
|
135
|
-
fireEvent.click(h3Button);
|
136
|
-
|
137
|
-
expect(baseElement.querySelector('div.remirror-editor h3')).toBeTruthy();
|
138
|
-
});
|
139
|
-
|
140
|
-
it('Applies Heading 4 styling to text when clicked', () => {
|
141
|
-
const { baseElement } = render(<Editor />);
|
142
|
-
expect(baseElement).toBeTruthy();
|
143
|
-
|
144
|
-
expect(baseElement.querySelector('div.remirror-editor h4')).toBeFalsy();
|
145
|
-
|
146
|
-
const headingDropdown = baseElement.querySelector('.toolbar-dropdown__button') as HTMLButtonElement;
|
147
|
-
expect(headingDropdown).toBeTruthy();
|
148
|
-
fireEvent.click(headingDropdown);
|
149
|
-
|
150
|
-
const h4Button = baseElement.querySelector('button[title="Heading 4"]') as HTMLButtonElement;
|
151
|
-
expect(h4Button).toBeTruthy();
|
152
|
-
fireEvent.click(h4Button);
|
153
|
-
|
154
|
-
expect(baseElement.querySelector('div.remirror-editor h4')).toBeTruthy();
|
155
|
-
});
|
156
|
-
|
157
|
-
it('Applies Heading 5 styling to text when clicked', () => {
|
158
|
-
const { baseElement } = render(<Editor />);
|
159
|
-
expect(baseElement).toBeTruthy();
|
160
|
-
|
161
|
-
expect(baseElement.querySelector('div.remirror-editor h5')).toBeFalsy();
|
162
|
-
|
163
|
-
const headingDropdown = baseElement.querySelector('.toolbar-dropdown__button') as HTMLButtonElement;
|
164
|
-
expect(headingDropdown).toBeTruthy();
|
165
|
-
fireEvent.click(headingDropdown);
|
166
|
-
|
167
|
-
const h5Button = baseElement.querySelector('button[title="Heading 5"]') as HTMLButtonElement;
|
168
|
-
expect(h5Button).toBeTruthy();
|
169
|
-
fireEvent.click(h5Button);
|
170
|
-
|
171
|
-
expect(baseElement.querySelector('div.remirror-editor h5')).toBeTruthy();
|
172
|
-
});
|
173
|
-
|
174
|
-
it('Applies Heading 6 styling to text when clicked', () => {
|
175
|
-
const { baseElement } = render(<Editor />);
|
176
|
-
expect(baseElement).toBeTruthy();
|
177
|
-
|
178
|
-
expect(baseElement.querySelector('div.remirror-editor h6')).toBeFalsy();
|
179
|
-
|
180
|
-
const headingDropdown = baseElement.querySelector('.toolbar-dropdown__button') as HTMLButtonElement;
|
181
|
-
expect(headingDropdown).toBeTruthy();
|
182
|
-
fireEvent.click(headingDropdown);
|
183
|
-
|
184
|
-
const h6Button = baseElement.querySelector('button[title="Heading 6"]') as HTMLButtonElement;
|
185
|
-
expect(h6Button).toBeTruthy();
|
186
|
-
fireEvent.click(h6Button);
|
187
|
-
|
188
|
-
expect(baseElement.querySelector('div.remirror-editor h6')).toBeTruthy();
|
189
|
-
});
|
190
|
-
|
191
|
-
it('Applies Preformatted styling to text when clicked', () => {
|
192
|
-
const { baseElement } = render(<Editor />);
|
193
|
-
expect(baseElement).toBeTruthy();
|
194
|
-
|
195
|
-
expect(baseElement.querySelector('div.remirror-editor pre')).toBeFalsy();
|
196
|
-
|
197
|
-
const headingDropdown = baseElement.querySelector('.toolbar-dropdown__button') as HTMLButtonElement;
|
198
|
-
expect(headingDropdown).toBeTruthy();
|
199
|
-
fireEvent.click(headingDropdown);
|
200
|
-
|
201
|
-
const preButton = baseElement.querySelector('button[title="Preformatted"]') as HTMLButtonElement;
|
202
|
-
expect(preButton).toBeTruthy();
|
203
|
-
fireEvent.click(preButton);
|
204
|
-
|
205
|
-
expect(baseElement.querySelector('div.remirror-editor pre')).toBeTruthy();
|
206
|
-
});
|
207
|
-
|
208
|
-
it('Applies Paragraph styling to text when clicked', () => {
|
209
|
-
const { baseElement } = render(<Editor />);
|
210
|
-
expect(baseElement).toBeTruthy();
|
211
|
-
|
212
|
-
expect(baseElement.querySelectorAll('div.remirror-editor p')).toHaveLength(1);
|
213
|
-
|
214
|
-
const headingDropdown = baseElement.querySelector('.toolbar-dropdown__button') as HTMLButtonElement;
|
215
|
-
expect(headingDropdown).toBeTruthy();
|
216
|
-
fireEvent.click(headingDropdown);
|
217
|
-
|
218
|
-
const preButton = baseElement.querySelector('button[title="Preformatted"]') as HTMLButtonElement;
|
219
|
-
expect(preButton).toBeTruthy();
|
220
|
-
fireEvent.click(preButton);
|
221
|
-
|
222
|
-
const paragraphButton = baseElement.querySelector('button[title="Paragraph"]') as HTMLButtonElement;
|
223
|
-
expect(paragraphButton).toBeTruthy();
|
224
|
-
fireEvent.click(paragraphButton);
|
225
|
-
|
226
|
-
expect(baseElement.querySelectorAll('div.remirror-editor p')).toHaveLength(2);
|
227
|
-
});
|
228
|
-
});
|
package/src/Editor/Editor.tsx
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import {
|
3
|
-
BoldExtension,
|
4
|
-
HeadingExtension,
|
5
|
-
ItalicExtension,
|
6
|
-
NodeFormattingExtension,
|
7
|
-
ParagraphExtension,
|
8
|
-
UnderlineExtension,
|
9
|
-
HistoryExtension,
|
10
|
-
wysiwygPreset,
|
11
|
-
} from 'remirror/extensions';
|
12
|
-
import { EditorComponent, Remirror, useRemirror } from '@remirror/react';
|
13
|
-
import { RemirrorContentType, Extension } from '@remirror/core';
|
14
|
-
import { EditorToolbar } from '../EditorToolbar/EditorToolbar';
|
15
|
-
import { PreformattedExtension } from '../extensions/PreformattedExtension/PreformattedExtension';
|
16
|
-
|
17
|
-
type EditorProps = {
|
18
|
-
content?: RemirrorContentType;
|
19
|
-
};
|
20
|
-
|
21
|
-
const Editor = ({ content }: EditorProps) => {
|
22
|
-
const { manager, state, setState } = useRemirror({
|
23
|
-
extensions: () => [
|
24
|
-
...(wysiwygPreset() as Extension[]),
|
25
|
-
new BoldExtension(),
|
26
|
-
new HeadingExtension(),
|
27
|
-
new ItalicExtension(),
|
28
|
-
new NodeFormattingExtension(),
|
29
|
-
new ParagraphExtension(),
|
30
|
-
new PreformattedExtension(),
|
31
|
-
new UnderlineExtension(),
|
32
|
-
new HistoryExtension(),
|
33
|
-
],
|
34
|
-
content,
|
35
|
-
selection: 'start',
|
36
|
-
stringHandler: 'html',
|
37
|
-
});
|
38
|
-
|
39
|
-
const handleChange = (parameter: { state: any }) => {
|
40
|
-
setState(parameter.state);
|
41
|
-
};
|
42
|
-
|
43
|
-
return (
|
44
|
-
<Remirror manager={manager} state={state} onChange={handleChange} placeholder="Write something" label="Text editor">
|
45
|
-
<EditorToolbar manager={manager} />
|
46
|
-
<EditorComponent />
|
47
|
-
<EditorToolbar manager={manager} isPopover />
|
48
|
-
</Remirror>
|
49
|
-
);
|
50
|
-
};
|
51
|
-
|
52
|
-
export default Editor;
|
package/src/Editor/_editor.scss
DELETED
@@ -1,75 +0,0 @@
|
|
1
|
-
.formatted-text-editor {
|
2
|
-
font-family: 'Open Sans' !important;
|
3
|
-
|
4
|
-
&.editor-wrapper {
|
5
|
-
@apply bg-white rounded border-gray-300 border-2 border-solid;
|
6
|
-
}
|
7
|
-
|
8
|
-
.remirror-editor-wrapper {
|
9
|
-
@apply text-gray-600 pt-0;
|
10
|
-
}
|
11
|
-
|
12
|
-
.remirror-editor {
|
13
|
-
@apply bg-white shadow-none rounded-b;
|
14
|
-
|
15
|
-
&:active,
|
16
|
-
:focus {
|
17
|
-
/* some focus state */
|
18
|
-
}
|
19
|
-
|
20
|
-
p {
|
21
|
-
/* Make sure content aligned with "text-align: justify" is justified */
|
22
|
-
@apply block;
|
23
|
-
}
|
24
|
-
}
|
25
|
-
}
|
26
|
-
|
27
|
-
/* remove existing style */
|
28
|
-
.remirror-theme .ProseMirror {
|
29
|
-
&:active,
|
30
|
-
&:focus {
|
31
|
-
@apply shadow-none;
|
32
|
-
}
|
33
|
-
}
|
34
|
-
|
35
|
-
.remirror-theme h1 {
|
36
|
-
font-size: 1.625rem;
|
37
|
-
font-weight: 600;
|
38
|
-
letter-spacing: -0.2px;
|
39
|
-
line-height: 2rem;
|
40
|
-
}
|
41
|
-
|
42
|
-
.remirror-theme h2 {
|
43
|
-
font-size: 1.25rem;
|
44
|
-
font-weight: 600;
|
45
|
-
letter-spacing: -0.5px;
|
46
|
-
line-height: 1.5rem;
|
47
|
-
}
|
48
|
-
|
49
|
-
.remirror-theme h3 {
|
50
|
-
font-size: 1.125rem;
|
51
|
-
font-weight: 600;
|
52
|
-
letter-spacing: -0.2px;
|
53
|
-
line-height: 1.375rem;
|
54
|
-
}
|
55
|
-
|
56
|
-
.remirror-theme h4 {
|
57
|
-
font-size: 1rem;
|
58
|
-
font-weight: 700;
|
59
|
-
letter-spacing: -0.2px;
|
60
|
-
line-height: 1.25rem;
|
61
|
-
}
|
62
|
-
|
63
|
-
.remirror-theme h5 {
|
64
|
-
font-size: 1rem;
|
65
|
-
font-weight: 600;
|
66
|
-
letter-spacing: -0.2px;
|
67
|
-
line-height: 1.25rem;
|
68
|
-
}
|
69
|
-
|
70
|
-
.remirror-theme h6 {
|
71
|
-
font-size: 0.875rem;
|
72
|
-
font-weight: 600;
|
73
|
-
letter-spacing: -0.2px;
|
74
|
-
line-height: 1.25rem;
|
75
|
-
}
|
@@ -1,51 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import { Toolbar, FloatingToolbar, VerticalDivider } from '@remirror/react-components';
|
3
|
-
import { RemirrorManager } from 'remirror';
|
4
|
-
import ItalicButton from './Tools/Italic/ItalicButton';
|
5
|
-
import UnderlineButton from './Tools/Underline/UnderlineButton';
|
6
|
-
import BoldButton from './Tools/Bold/BoldButton';
|
7
|
-
import TextAlignButtons from './Tools/TextAlign/TextAlignButtons';
|
8
|
-
import UndoButton from './Tools/Undo/UndoButton';
|
9
|
-
import RedoButton from './Tools/Redo/RedoButton';
|
10
|
-
import TextTypeDropdown from './Tools/TextType/TextTypeDropdown';
|
11
|
-
|
12
|
-
type EditorToolbarProps = {
|
13
|
-
manager: RemirrorManager<any>;
|
14
|
-
isPopover?: boolean;
|
15
|
-
};
|
16
|
-
|
17
|
-
// The editor main toolbar
|
18
|
-
export const EditorToolbar = ({ manager, isPopover }: EditorToolbarProps) => {
|
19
|
-
const extensionNames: Record<string, true> = {};
|
20
|
-
|
21
|
-
manager.extensions.forEach((extension) => {
|
22
|
-
extensionNames[extension.name] = true;
|
23
|
-
});
|
24
|
-
|
25
|
-
return (
|
26
|
-
<>
|
27
|
-
{!isPopover ? (
|
28
|
-
<Toolbar className="remirror-toolbar editor-toolbar">
|
29
|
-
{extensionNames.history && (
|
30
|
-
<>
|
31
|
-
<UndoButton />
|
32
|
-
<RedoButton />
|
33
|
-
<VerticalDivider className="editor-divider" />
|
34
|
-
</>
|
35
|
-
)}
|
36
|
-
{extensionNames.heading && extensionNames.paragraph && extensionNames.preformatted && <TextTypeDropdown />}
|
37
|
-
{extensionNames.bold && <BoldButton />}
|
38
|
-
{extensionNames.italic && <ItalicButton />}
|
39
|
-
{extensionNames.underline && <UnderlineButton />}
|
40
|
-
{extensionNames.nodeFormatting && <TextAlignButtons />}
|
41
|
-
</Toolbar>
|
42
|
-
) : (
|
43
|
-
<FloatingToolbar className="remirror-floating-popover">
|
44
|
-
{extensionNames.bold && <BoldButton />}
|
45
|
-
{extensionNames.italic && <ItalicButton />}
|
46
|
-
{extensionNames.underline && <UnderlineButton />}
|
47
|
-
</FloatingToolbar>
|
48
|
-
)}
|
49
|
-
</>
|
50
|
-
);
|
51
|
-
};
|
@@ -1,19 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import '@testing-library/jest-dom';
|
3
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
4
|
-
import Editor from '../../../Editor/Editor';
|
5
|
-
|
6
|
-
describe('Bold button', () => {
|
7
|
-
it('Renders the bold button', () => {
|
8
|
-
render(<Editor />);
|
9
|
-
expect(screen.getByRole('button', { name: 'Bold (cmd+B)' })).toBeInTheDocument();
|
10
|
-
});
|
11
|
-
|
12
|
-
it('Activates the button if clicked', () => {
|
13
|
-
render(<Editor />);
|
14
|
-
expect(screen.getByRole('button', { name: 'Bold (cmd+B)' }).classList.contains('btn')).toBeTruthy();
|
15
|
-
const bold = screen.getByRole('button', { name: 'Bold (cmd+B)' });
|
16
|
-
fireEvent.click(bold);
|
17
|
-
expect(bold.classList.contains('is-active')).toBeTruthy();
|
18
|
-
});
|
19
|
-
});
|
@@ -1,30 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import { useCommands, useActive, useChainedCommands } from '@remirror/react';
|
3
|
-
import { BoldExtension } from '@remirror/extension-bold';
|
4
|
-
import ToolbarButton from '../../../ui/ToolbarButton/ToolbarButton';
|
5
|
-
import FormatBoldRoundedIcon from '@mui/icons-material/FormatBoldRounded';
|
6
|
-
|
7
|
-
const BoldButton = () => {
|
8
|
-
const { toggleBold } = useCommands();
|
9
|
-
const chain = useChainedCommands();
|
10
|
-
|
11
|
-
const active = useActive<BoldExtension>();
|
12
|
-
const enabled = toggleBold.enabled();
|
13
|
-
const handleSelect = () => {
|
14
|
-
if (toggleBold.enabled()) {
|
15
|
-
chain.toggleBold().focus().run();
|
16
|
-
}
|
17
|
-
};
|
18
|
-
|
19
|
-
return (
|
20
|
-
<ToolbarButton
|
21
|
-
handleOnClick={handleSelect}
|
22
|
-
isDisabled={!enabled}
|
23
|
-
isActive={active.bold()}
|
24
|
-
icon={<FormatBoldRoundedIcon />}
|
25
|
-
label="Bold (cmd+B)"
|
26
|
-
/>
|
27
|
-
);
|
28
|
-
};
|
29
|
-
|
30
|
-
export default BoldButton;
|
@@ -1,19 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import '@testing-library/jest-dom';
|
3
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
4
|
-
import Editor from '../../../Editor/Editor';
|
5
|
-
|
6
|
-
describe('Italic button', () => {
|
7
|
-
it('Renders the italic button', () => {
|
8
|
-
render(<Editor />);
|
9
|
-
expect(screen.getByRole('button', { name: 'Italic (cmd+I)' })).toBeInTheDocument();
|
10
|
-
});
|
11
|
-
|
12
|
-
it('Activates the button if clicked', () => {
|
13
|
-
render(<Editor />);
|
14
|
-
expect(screen.getByRole('button', { name: 'Italic (cmd+I)' }).classList.contains('btn')).toBeTruthy();
|
15
|
-
const italic = screen.getByRole('button', { name: 'Italic (cmd+I)' });
|
16
|
-
fireEvent.click(italic);
|
17
|
-
expect(italic.classList.contains('is-active')).toBeTruthy();
|
18
|
-
});
|
19
|
-
});
|
@@ -1,30 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import { useCommands, useActive, useChainedCommands } from '@remirror/react';
|
3
|
-
import { ItalicExtension } from '@remirror/extension-italic';
|
4
|
-
import ToolbarButton from '../../../ui/ToolbarButton/ToolbarButton';
|
5
|
-
import FormatItalicRoundedIcon from '@mui/icons-material/FormatItalicRounded';
|
6
|
-
|
7
|
-
const ItalicButton = () => {
|
8
|
-
const { toggleItalic } = useCommands();
|
9
|
-
const chain = useChainedCommands();
|
10
|
-
|
11
|
-
const active = useActive<ItalicExtension>();
|
12
|
-
const enabled = toggleItalic.enabled();
|
13
|
-
const handleSelect = () => {
|
14
|
-
if (toggleItalic.enabled()) {
|
15
|
-
chain.toggleItalic().focus().run();
|
16
|
-
}
|
17
|
-
};
|
18
|
-
|
19
|
-
return (
|
20
|
-
<ToolbarButton
|
21
|
-
handleOnClick={handleSelect}
|
22
|
-
isDisabled={!enabled}
|
23
|
-
isActive={active.italic()}
|
24
|
-
icon={<FormatItalicRoundedIcon />}
|
25
|
-
label="Italic (cmd+I)"
|
26
|
-
/>
|
27
|
-
);
|
28
|
-
};
|
29
|
-
|
30
|
-
export default ItalicButton;
|
@@ -1,59 +0,0 @@
|
|
1
|
-
import '@testing-library/jest-dom';
|
2
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
3
|
-
import Editor from '../../../Editor/Editor';
|
4
|
-
import React from 'react';
|
5
|
-
|
6
|
-
describe('Redo button', () => {
|
7
|
-
it('Renders the redo button', () => {
|
8
|
-
render(<Editor />);
|
9
|
-
expect(screen.getByRole('button', { name: 'Redo (shift+cmd+Z)' })).toBeInTheDocument();
|
10
|
-
});
|
11
|
-
|
12
|
-
it('Renders a disabled button if you have not made any changes yet', () => {
|
13
|
-
render(<Editor />);
|
14
|
-
const redo = screen.getByRole('button', { name: 'Redo (shift+cmd+Z)' });
|
15
|
-
expect(redo).toBeDisabled();
|
16
|
-
});
|
17
|
-
|
18
|
-
it('Enables the button when you perform an action and then revert it', () => {
|
19
|
-
const { baseElement } = render(<Editor />);
|
20
|
-
|
21
|
-
// perform some action
|
22
|
-
const leftAlignButton = baseElement.querySelector('button[title="Align left"]') as HTMLButtonElement;
|
23
|
-
expect(leftAlignButton).toBeTruthy();
|
24
|
-
fireEvent.click(leftAlignButton);
|
25
|
-
expect(baseElement.querySelector('p[data-node-text-align="left"]')).toBeTruthy();
|
26
|
-
|
27
|
-
// Revert this action
|
28
|
-
const undo = screen.getByRole('button', { name: 'Undo (cmd+Z)' });
|
29
|
-
fireEvent.click(undo);
|
30
|
-
expect(baseElement.querySelector('p[data-node-text-align="left"]')).toBeFalsy();
|
31
|
-
|
32
|
-
// Check that this enables the redo button
|
33
|
-
const redo = screen.getByRole('button', { name: 'Redo (shift+cmd+Z)' });
|
34
|
-
expect(redo).not.toBeDisabled();
|
35
|
-
});
|
36
|
-
|
37
|
-
it('Reverts this action when clicked', () => {
|
38
|
-
const { baseElement } = render(<Editor />);
|
39
|
-
|
40
|
-
// perform some action
|
41
|
-
const leftAlignButton = baseElement.querySelector('button[title="Align left"]') as HTMLButtonElement;
|
42
|
-
expect(leftAlignButton).toBeTruthy();
|
43
|
-
fireEvent.click(leftAlignButton);
|
44
|
-
expect(baseElement.querySelector('p[data-node-text-align="left"]')).toBeTruthy();
|
45
|
-
|
46
|
-
// Revert this action
|
47
|
-
const undo = screen.getByRole('button', { name: 'Undo (cmd+Z)' });
|
48
|
-
fireEvent.click(undo);
|
49
|
-
expect(baseElement.querySelector('p[data-node-text-align="left"]')).toBeFalsy();
|
50
|
-
|
51
|
-
// Check that this enables the redo button
|
52
|
-
const redo = screen.getByRole('button', { name: 'Redo (shift+cmd+Z)' });
|
53
|
-
expect(redo).not.toBeDisabled();
|
54
|
-
|
55
|
-
// Click the redo button and check that this has reverted the previous action
|
56
|
-
fireEvent.click(redo);
|
57
|
-
expect(baseElement.querySelector('p[data-node-text-align="left"]')).toBeTruthy();
|
58
|
-
});
|
59
|
-
});
|