@squiz/formatted-text-editor 1.12.0-alpha.14 → 1.12.0-alpha.16
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/Editor/Editor.js +3 -2
- package/lib/EditorToolbar/EditorToolbar.js +7 -1
- package/lib/EditorToolbar/Tools/Redo/RedoButton.d.ts +2 -0
- package/lib/EditorToolbar/Tools/Redo/RedoButton.js +16 -0
- package/lib/EditorToolbar/Tools/Undo/UndoButton.d.ts +2 -0
- package/lib/EditorToolbar/Tools/Undo/UndoButton.js +16 -0
- package/lib/index.css +2 -1
- package/package.json +2 -2
- package/src/Editor/Editor.tsx +3 -1
- package/src/EditorToolbar/EditorToolbar.tsx +10 -1
- package/src/EditorToolbar/Tools/Redo/RedoButton.spec.tsx +59 -0
- package/src/EditorToolbar/Tools/Redo/RedoButton.tsx +30 -0
- package/src/EditorToolbar/Tools/Undo/UndoButton.spec.tsx +49 -0
- package/src/EditorToolbar/Tools/Undo/UndoButton.tsx +30 -0
- package/src/EditorToolbar/editor-toolbar.scss +0 -1
- package/src/ui/ToolbarButton/toolbar-button.scss +2 -1
package/lib/Editor/Editor.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { BoldExtension, ItalicExtension, NodeFormattingExtension, UnderlineExtension, wysiwygPreset, } from 'remirror/extensions';
|
2
|
+
import { BoldExtension, ItalicExtension, NodeFormattingExtension, UnderlineExtension, HistoryExtension, wysiwygPreset, } from 'remirror/extensions';
|
3
3
|
import { EditorComponent, Remirror, useRemirror } from '@remirror/react';
|
4
4
|
import { EditorToolbar } from '../EditorToolbar/EditorToolbar';
|
5
5
|
const Editor = ({ content }) => {
|
@@ -10,6 +10,7 @@ const Editor = ({ content }) => {
|
|
10
10
|
new ItalicExtension(),
|
11
11
|
new NodeFormattingExtension(),
|
12
12
|
new UnderlineExtension(),
|
13
|
+
new HistoryExtension(),
|
13
14
|
],
|
14
15
|
content,
|
15
16
|
selection: 'start',
|
@@ -18,7 +19,7 @@ const Editor = ({ content }) => {
|
|
18
19
|
const handleChange = (parameter) => {
|
19
20
|
setState(parameter.state);
|
20
21
|
};
|
21
|
-
return (React.createElement(Remirror, { manager: manager, state: state, onChange: handleChange, placeholder: "Write something" },
|
22
|
+
return (React.createElement(Remirror, { manager: manager, state: state, onChange: handleChange, placeholder: "Write something", label: "Text editor" },
|
22
23
|
React.createElement(EditorToolbar, { manager: manager }),
|
23
24
|
React.createElement(EditorComponent, null),
|
24
25
|
React.createElement(EditorToolbar, { manager: manager, isPopover: true })));
|
@@ -1,9 +1,11 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { Toolbar, FloatingToolbar } from '@remirror/react-components';
|
2
|
+
import { Toolbar, FloatingToolbar, VerticalDivider } from '@remirror/react-components';
|
3
3
|
import ItalicButton from './Tools/Italic/ItalicButton';
|
4
4
|
import UnderlineButton from './Tools/Underline/UnderlineButton';
|
5
5
|
import BoldButton from './Tools/Bold/BoldButton';
|
6
6
|
import TextAlignButtons from './Tools/TextAlign/TextAlignButtons';
|
7
|
+
import UndoButton from './Tools/Undo/UndoButton';
|
8
|
+
import RedoButton from './Tools/Redo/RedoButton';
|
7
9
|
// The editor main toolbar
|
8
10
|
export const EditorToolbar = ({ manager, isPopover }) => {
|
9
11
|
const extensionNames = {};
|
@@ -11,6 +13,10 @@ export const EditorToolbar = ({ manager, isPopover }) => {
|
|
11
13
|
extensionNames[extension.name] = true;
|
12
14
|
});
|
13
15
|
return (React.createElement(React.Fragment, null, !isPopover ? (React.createElement(Toolbar, { className: "remirror-toolbar editor-toolbar" },
|
16
|
+
extensionNames.history && (React.createElement(React.Fragment, null,
|
17
|
+
React.createElement(UndoButton, null),
|
18
|
+
React.createElement(RedoButton, null),
|
19
|
+
React.createElement(VerticalDivider, { className: "editor-divider" }))),
|
14
20
|
extensionNames.bold && React.createElement(BoldButton, null),
|
15
21
|
extensionNames.italic && React.createElement(ItalicButton, null),
|
16
22
|
extensionNames.underline && React.createElement(UnderlineButton, null),
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useCommands, useHelpers } from '@remirror/react';
|
3
|
+
import ToolbarButton from '../../../ui/ToolbarButton/ToolbarButton';
|
4
|
+
import RedoRoundedIcon from '@mui/icons-material/RedoRounded';
|
5
|
+
const RedoButton = () => {
|
6
|
+
const { redo } = useCommands();
|
7
|
+
const { redoDepth } = useHelpers(true);
|
8
|
+
const handleSelect = () => {
|
9
|
+
if (redo.enabled()) {
|
10
|
+
redo();
|
11
|
+
}
|
12
|
+
};
|
13
|
+
const enabled = redoDepth() > 0;
|
14
|
+
return (React.createElement(ToolbarButton, { handleOnClick: handleSelect, isDisabled: !enabled, isActive: false, icon: React.createElement(RedoRoundedIcon, null), label: "Redo (shift+cmd+Z)" }));
|
15
|
+
};
|
16
|
+
export default RedoButton;
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useCommands, useHelpers } from '@remirror/react';
|
3
|
+
import ToolbarButton from '../../../ui/ToolbarButton/ToolbarButton';
|
4
|
+
import UndoRoundedIcon from '@mui/icons-material/UndoRounded';
|
5
|
+
const UndoButton = () => {
|
6
|
+
const { undo } = useCommands();
|
7
|
+
const { undoDepth } = useHelpers(true);
|
8
|
+
const handleSelect = () => {
|
9
|
+
if (undo.enabled()) {
|
10
|
+
undo();
|
11
|
+
}
|
12
|
+
};
|
13
|
+
const enabled = undoDepth() > 0;
|
14
|
+
return (React.createElement(ToolbarButton, { handleOnClick: handleSelect, isDisabled: !enabled, isActive: false, icon: React.createElement(UndoRoundedIcon, null), label: "Undo (cmd+Z)" }));
|
15
|
+
};
|
16
|
+
export default UndoButton;
|
package/lib/index.css
CHANGED
@@ -3843,7 +3843,8 @@ button:active .remirror-menu-pane-shortcut,
|
|
3843
3843
|
.toolbar-button ~ .toolbar-button {
|
3844
3844
|
margin-left: 2px;
|
3845
3845
|
}
|
3846
|
-
.toolbar-button.is-active
|
3846
|
+
.toolbar-button.is-active,
|
3847
|
+
.toolbar-button:active {
|
3847
3848
|
background-color: var(--blue-100);
|
3848
3849
|
color: var(--blue-300);
|
3849
3850
|
}
|
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.16",
|
4
4
|
"main": "lib/index.js",
|
5
5
|
"types": "lib/index.d.ts",
|
6
6
|
"scripts": {
|
@@ -55,5 +55,5 @@
|
|
55
55
|
"volta": {
|
56
56
|
"node": "16.19.0"
|
57
57
|
},
|
58
|
-
"gitHead": "
|
58
|
+
"gitHead": "25328af157198a2b393ebab5896efa9b28cbdd69"
|
59
59
|
}
|
package/src/Editor/Editor.tsx
CHANGED
@@ -4,6 +4,7 @@ import {
|
|
4
4
|
ItalicExtension,
|
5
5
|
NodeFormattingExtension,
|
6
6
|
UnderlineExtension,
|
7
|
+
HistoryExtension,
|
7
8
|
wysiwygPreset,
|
8
9
|
} from 'remirror/extensions';
|
9
10
|
import { EditorComponent, Remirror, useRemirror } from '@remirror/react';
|
@@ -22,6 +23,7 @@ const Editor = ({ content }: EditorProps) => {
|
|
22
23
|
new ItalicExtension(),
|
23
24
|
new NodeFormattingExtension(),
|
24
25
|
new UnderlineExtension(),
|
26
|
+
new HistoryExtension(),
|
25
27
|
],
|
26
28
|
content,
|
27
29
|
selection: 'start',
|
@@ -33,7 +35,7 @@ const Editor = ({ content }: EditorProps) => {
|
|
33
35
|
};
|
34
36
|
|
35
37
|
return (
|
36
|
-
<Remirror manager={manager} state={state} onChange={handleChange} placeholder="Write something">
|
38
|
+
<Remirror manager={manager} state={state} onChange={handleChange} placeholder="Write something" label="Text editor">
|
37
39
|
<EditorToolbar manager={manager} />
|
38
40
|
<EditorComponent />
|
39
41
|
<EditorToolbar manager={manager} isPopover />
|
@@ -1,10 +1,12 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { Toolbar, FloatingToolbar } from '@remirror/react-components';
|
2
|
+
import { Toolbar, FloatingToolbar, VerticalDivider } from '@remirror/react-components';
|
3
3
|
import { RemirrorManager } from 'remirror';
|
4
4
|
import ItalicButton from './Tools/Italic/ItalicButton';
|
5
5
|
import UnderlineButton from './Tools/Underline/UnderlineButton';
|
6
6
|
import BoldButton from './Tools/Bold/BoldButton';
|
7
7
|
import TextAlignButtons from './Tools/TextAlign/TextAlignButtons';
|
8
|
+
import UndoButton from './Tools/Undo/UndoButton';
|
9
|
+
import RedoButton from './Tools/Redo/RedoButton';
|
8
10
|
|
9
11
|
type EditorToolbarProps = {
|
10
12
|
manager: RemirrorManager<any>;
|
@@ -23,6 +25,13 @@ export const EditorToolbar = ({ manager, isPopover }: EditorToolbarProps) => {
|
|
23
25
|
<>
|
24
26
|
{!isPopover ? (
|
25
27
|
<Toolbar className="remirror-toolbar editor-toolbar">
|
28
|
+
{extensionNames.history && (
|
29
|
+
<>
|
30
|
+
<UndoButton />
|
31
|
+
<RedoButton />
|
32
|
+
<VerticalDivider className="editor-divider" />
|
33
|
+
</>
|
34
|
+
)}
|
26
35
|
{extensionNames.bold && <BoldButton />}
|
27
36
|
{extensionNames.italic && <ItalicButton />}
|
28
37
|
{extensionNames.underline && <UnderlineButton />}
|
@@ -0,0 +1,59 @@
|
|
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
|
+
});
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useCommands, useHelpers } from '@remirror/react';
|
3
|
+
import { HistoryExtension } from 'remirror/extensions';
|
4
|
+
import ToolbarButton from '../../../ui/ToolbarButton/ToolbarButton';
|
5
|
+
import RedoRoundedIcon from '@mui/icons-material/RedoRounded';
|
6
|
+
|
7
|
+
const RedoButton = () => {
|
8
|
+
const { redo } = useCommands<HistoryExtension>();
|
9
|
+
const { redoDepth } = useHelpers<HistoryExtension>(true);
|
10
|
+
|
11
|
+
const handleSelect = () => {
|
12
|
+
if (redo.enabled()) {
|
13
|
+
redo();
|
14
|
+
}
|
15
|
+
};
|
16
|
+
|
17
|
+
const enabled = redoDepth() > 0;
|
18
|
+
|
19
|
+
return (
|
20
|
+
<ToolbarButton
|
21
|
+
handleOnClick={handleSelect}
|
22
|
+
isDisabled={!enabled}
|
23
|
+
isActive={false}
|
24
|
+
icon={<RedoRoundedIcon />}
|
25
|
+
label="Redo (shift+cmd+Z)"
|
26
|
+
/>
|
27
|
+
);
|
28
|
+
};
|
29
|
+
|
30
|
+
export default RedoButton;
|
@@ -0,0 +1,49 @@
|
|
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('Undo button', () => {
|
7
|
+
it('Renders the undo button', () => {
|
8
|
+
render(<Editor />);
|
9
|
+
expect(screen.getByRole('button', { name: 'Undo (cmd+Z)' })).toBeInTheDocument();
|
10
|
+
});
|
11
|
+
|
12
|
+
it('Renders a disabled button if you have not made any changes yet', () => {
|
13
|
+
render(<Editor />);
|
14
|
+
const undo = screen.getByRole('button', { name: 'Undo (cmd+Z)' });
|
15
|
+
expect(undo).toBeDisabled();
|
16
|
+
});
|
17
|
+
|
18
|
+
it('Enables the button when you perform an action', () => {
|
19
|
+
const { baseElement } = render(<Editor />);
|
20
|
+
expect(baseElement.querySelector('p[data-node-text-align="left"]')).toBeFalsy();
|
21
|
+
|
22
|
+
const leftAlignButton = baseElement.querySelector('button[title="Align left"]') as HTMLButtonElement;
|
23
|
+
expect(leftAlignButton).toBeTruthy();
|
24
|
+
|
25
|
+
fireEvent.click(leftAlignButton);
|
26
|
+
expect(baseElement.querySelector('p[data-node-text-align="left"]')).toBeTruthy();
|
27
|
+
const undo = screen.getByRole('button', { name: 'Undo (cmd+Z)' });
|
28
|
+
expect(undo).not.toBeDisabled();
|
29
|
+
});
|
30
|
+
|
31
|
+
it('Reverts this action when clicked', () => {
|
32
|
+
const { baseElement } = render(<Editor />);
|
33
|
+
|
34
|
+
// perform some action
|
35
|
+
expect(baseElement.querySelector('p[data-node-text-align="left"]')).toBeFalsy();
|
36
|
+
const leftAlignButton = baseElement.querySelector('button[title="Align left"]') as HTMLButtonElement;
|
37
|
+
expect(leftAlignButton).toBeTruthy();
|
38
|
+
fireEvent.click(leftAlignButton);
|
39
|
+
expect(baseElement.querySelector('p[data-node-text-align="left"]')).toBeTruthy();
|
40
|
+
|
41
|
+
// Check that this enables the undo button
|
42
|
+
const undo = screen.getByRole('button', { name: 'Undo (cmd+Z)' });
|
43
|
+
expect(undo).not.toBeDisabled();
|
44
|
+
|
45
|
+
// Click the undo button and check that this has reverted the previous action
|
46
|
+
fireEvent.click(undo);
|
47
|
+
expect(baseElement.querySelector('p[data-node-text-align="left"]')).toBeFalsy();
|
48
|
+
});
|
49
|
+
});
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useCommands, useHelpers } from '@remirror/react';
|
3
|
+
import { HistoryExtension } from 'remirror/extensions';
|
4
|
+
import ToolbarButton from '../../../ui/ToolbarButton/ToolbarButton';
|
5
|
+
import UndoRoundedIcon from '@mui/icons-material/UndoRounded';
|
6
|
+
|
7
|
+
const UndoButton = () => {
|
8
|
+
const { undo } = useCommands<HistoryExtension>();
|
9
|
+
const { undoDepth } = useHelpers<HistoryExtension>(true);
|
10
|
+
|
11
|
+
const handleSelect = () => {
|
12
|
+
if (undo.enabled()) {
|
13
|
+
undo();
|
14
|
+
}
|
15
|
+
};
|
16
|
+
|
17
|
+
const enabled = undoDepth() > 0;
|
18
|
+
|
19
|
+
return (
|
20
|
+
<ToolbarButton
|
21
|
+
handleOnClick={handleSelect}
|
22
|
+
isDisabled={!enabled}
|
23
|
+
isActive={false}
|
24
|
+
icon={<UndoRoundedIcon />}
|
25
|
+
label="Undo (cmd+Z)"
|
26
|
+
/>
|
27
|
+
);
|
28
|
+
};
|
29
|
+
|
30
|
+
export default UndoButton;
|