@squiz/formatted-text-editor 1.5.1-alpha.6 → 1.12.0-alpha.10
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 +81 -16
- package/lib/Editor/Editor.d.ts +6 -0
- package/lib/Editor/Editor.js +26 -0
- package/lib/EditorToolbar/EditorToolbar.d.ts +7 -0
- package/lib/EditorToolbar/EditorToolbar.js +21 -0
- package/lib/EditorToolbar/Tools/Bold/BoldButton.d.ts +2 -0
- package/lib/EditorToolbar/Tools/Bold/BoldButton.js +17 -0
- package/lib/EditorToolbar/Tools/Italic/ItalicButton.d.ts +2 -0
- package/lib/EditorToolbar/Tools/Italic/ItalicButton.js +17 -0
- package/lib/EditorToolbar/Tools/TextAlign/CenterAlign/CenterAlignButton.d.ts +2 -0
- package/lib/EditorToolbar/Tools/TextAlign/CenterAlign/CenterAlignButton.js +17 -0
- package/lib/EditorToolbar/Tools/TextAlign/JustifyAlign/JustifyAlignButton.d.ts +2 -0
- package/lib/EditorToolbar/Tools/TextAlign/JustifyAlign/JustifyAlignButton.js +17 -0
- package/lib/EditorToolbar/Tools/TextAlign/LeftAlign/LeftAlignButton.d.ts +2 -0
- package/lib/EditorToolbar/Tools/TextAlign/LeftAlign/LeftAlignButton.js +17 -0
- package/lib/EditorToolbar/Tools/TextAlign/RightAlign/RightAlignButton.d.ts +2 -0
- package/lib/EditorToolbar/Tools/TextAlign/RightAlign/RightAlignButton.js +17 -0
- package/lib/EditorToolbar/Tools/TextAlign/TextAlignButtons.d.ts +2 -0
- package/lib/EditorToolbar/Tools/TextAlign/TextAlignButtons.js +16 -0
- package/lib/EditorToolbar/Tools/Underline/UnderlineButton.d.ts +2 -0
- package/lib/EditorToolbar/Tools/Underline/UnderlineButton.js +17 -0
- package/lib/FormattedTextEditor.d.ts +2 -0
- package/lib/FormattedTextEditor.js +7 -0
- package/lib/index.css +3846 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -36344
- package/lib/ui/ToolbarButton/ToolbarButton.d.ts +10 -0
- package/lib/ui/ToolbarButton/ToolbarButton.js +5 -0
- package/package.json +47 -28
- package/.eslintignore +0 -6
- package/.eslintrc.json +0 -28
- package/CHANGELOG.md +0 -8
- package/index.html +0 -13
- package/lib/favicon-dxp.svg +0 -3
- package/lib/style.css +0 -1
- package/public/favicon-dxp.svg +0 -3
- package/src/App.tsx +0 -11
- package/src/FormattedTextEditor.tsx +0 -25
- package/src/Menu.tsx +0 -19
- package/src/Toolbar.tsx +0 -10
- package/src/index.css +0 -3
- package/src/main.tsx +0 -13
- package/src/toolbar.css +0 -9
- package/src/vite-env.d.ts +0 -1
- package/tsconfig.json +0 -21
- package/tsconfig.node.json +0 -9
- package/vite.config.ts +0 -17
package/README.md
CHANGED
@@ -1,37 +1,102 @@
|
|
1
1
|
# DXP Formatted text editor component
|
2
2
|
|
3
|
-
|
3
|
+
The Squiz DXP formatted text editor, built using [Remirror](https://remirror.io/) React library.
|
4
4
|
|
5
|
-
|
5
|
+
It is intended that this package is used for implementing rich text editor capabilities using the DXP Content Store.
|
6
|
+
|
7
|
+
## Tools and requirements
|
8
|
+
|
9
|
+
Tools that relate to standards, publishing and code base health should be available from the monorepo root. Package specific tools and requirements will be listed below.
|
6
10
|
|
7
11
|
### Requirements
|
8
12
|
|
9
|
-
|
10
|
-
- [Node/NPM](https://nodejs.org/en/)
|
13
|
+
There are no tools that you need locally that are specific to this repo. Please refer to the monorepo README for more information.
|
11
14
|
|
12
|
-
###
|
15
|
+
### Optional tools
|
13
16
|
|
14
|
-
Provided you have `Volta` installed as soon as you are in the `formatted-text-editor` directory you should be on the correct Node version.
|
15
|
-
See the `package.json` for the specific version.
|
17
|
+
- [Volta](https://volta.sh/): Provided you have `Volta` installed as soon as you are in the `formatted-text-editor` directory you should be on the correct Node version.
|
16
18
|
|
17
|
-
|
19
|
+
## Working locally
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
### Installation
|
22
|
+
|
23
|
+
Please refer to the monorepo README for getting up and running.
|
24
|
+
|
25
|
+
### Local development
|
26
|
+
|
27
|
+
You can preview the formatted text editor in your local environment by running the following command from the `packages/formatted-text-editor` directory:
|
22
28
|
|
23
29
|
```sh
|
24
30
|
npm run dev
|
25
31
|
```
|
32
|
+
|
26
33
|
This will expose `http://localhost:5173/` and this can be viewed in the browser.
|
27
34
|
|
35
|
+
> TIP: Make sure you have already installed the node modules at the root level of the repo.
|
36
|
+
|
37
|
+
### Testing
|
38
|
+
|
39
|
+
Tests must be written when contributing to this package. Tests are automatically run in CI and test failure will result in unmerged code.
|
40
|
+
|
41
|
+
#### Unit testing
|
42
|
+
|
43
|
+
This package using Jest to perform Unit testing. In addition to Jest we are using a few Testing Library utilities:
|
44
|
+
|
45
|
+
- [React testing library](https://testing-library.com/docs/react-testing-library/intro/) - Enables React component testing
|
46
|
+
- [Jest DOM](https://testing-library.com/docs/ecosystem-jest-dom/) - Enables custom matchers
|
47
|
+
|
48
|
+
Tests should be co-located with componentry and should strive for maximum coverage.
|
49
|
+
|
50
|
+
To run tests locally you can run:
|
51
|
+
```sh
|
52
|
+
npm run test
|
53
|
+
```
|
54
|
+
Or if you'd like to "watch" for changes:
|
55
|
+
```sh
|
56
|
+
npm run test:watch
|
57
|
+
```
|
58
|
+
|
59
|
+
#### End to end testing
|
60
|
+
|
61
|
+
This package uses [Cypress](https://docs.cypress.io/) for end to end testing.
|
62
|
+
|
63
|
+
To run tests locally you can run:
|
64
|
+
```sh
|
65
|
+
npm run test:e2e
|
66
|
+
```
|
67
|
+
Cypress is configured to look at a preview dev environment on `http://localhost:8080`.
|
68
|
+
|
69
|
+
|
70
|
+
## Publishing
|
71
|
+
|
72
|
+
This package will be automatically compiled and published following the process defined by the monorepo. Please see the README at the root of the monorepo for more details.
|
28
73
|
|
29
|
-
|
74
|
+
We may manually publish this repo following these steps (please note that you should only ever do this from the `develop` branch):
|
30
75
|
|
31
|
-
|
76
|
+
1. Run a clean, CI install, compile and publish from the root directory
|
32
77
|
|
33
|
-
|
78
|
+
```
|
79
|
+
npm run clean:all
|
80
|
+
npm ci
|
81
|
+
npm run compile
|
82
|
+
npx lerna publish -y --conventional-commits --ci --exact --conventional-prerelease
|
83
|
+
```
|
34
84
|
|
35
|
-
|
85
|
+
2. Move into the editor directory and check that the lib directory looks correct for publishing
|
36
86
|
|
37
|
-
|
87
|
+
```
|
88
|
+
cd packages/formatted-text-editor
|
89
|
+
ls -la packages/formatted-text-editor/lib
|
90
|
+
```
|
91
|
+
|
92
|
+
3. Execute the NPM publishing command from the package. Watch for any errors in the console
|
93
|
+
|
94
|
+
```
|
95
|
+
npm publish
|
96
|
+
```
|
97
|
+
|
98
|
+
4. Check that the package was published and pushed to NPM
|
99
|
+
|
100
|
+
```
|
101
|
+
npm view @squiz/formatted-text-editor
|
102
|
+
```
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { BoldExtension, ItalicExtension, NodeFormattingExtension, UnderlineExtension, wysiwygPreset, } from 'remirror/extensions';
|
3
|
+
import { EditorComponent, Remirror, useRemirror } from '@remirror/react';
|
4
|
+
import { EditorToolbar } from '../EditorToolbar/EditorToolbar';
|
5
|
+
const Editor = ({ content }) => {
|
6
|
+
const { manager, state, setState } = useRemirror({
|
7
|
+
extensions: () => [
|
8
|
+
...wysiwygPreset(),
|
9
|
+
new BoldExtension(),
|
10
|
+
new ItalicExtension(),
|
11
|
+
new NodeFormattingExtension(),
|
12
|
+
new UnderlineExtension(),
|
13
|
+
],
|
14
|
+
content,
|
15
|
+
selection: 'start',
|
16
|
+
stringHandler: 'html',
|
17
|
+
});
|
18
|
+
const handleChange = (parameter) => {
|
19
|
+
setState(parameter.state);
|
20
|
+
};
|
21
|
+
return (React.createElement(Remirror, { manager: manager, state: state, onChange: handleChange, placeholder: "Write something" },
|
22
|
+
React.createElement(EditorToolbar, { manager: manager }),
|
23
|
+
React.createElement(EditorComponent, null),
|
24
|
+
React.createElement(EditorToolbar, { manager: manager, isPopover: true })));
|
25
|
+
};
|
26
|
+
export default Editor;
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { Toolbar, FloatingToolbar } from '@remirror/react-components';
|
3
|
+
import ItalicButton from './Tools/Italic/ItalicButton';
|
4
|
+
import UnderlineButton from './Tools/Underline/UnderlineButton';
|
5
|
+
import BoldButton from './Tools/Bold/BoldButton';
|
6
|
+
import TextAlignButtons from './Tools/TextAlign/TextAlignButtons';
|
7
|
+
// The editor main toolbar
|
8
|
+
export const EditorToolbar = ({ manager, isPopover }) => {
|
9
|
+
const extensionNames = {};
|
10
|
+
manager.extensions.forEach((extension) => {
|
11
|
+
extensionNames[extension.name] = true;
|
12
|
+
});
|
13
|
+
return (React.createElement(React.Fragment, null, !isPopover ? (React.createElement(Toolbar, { className: "remirror-toolbar editor-toolbar" },
|
14
|
+
extensionNames.bold && React.createElement(BoldButton, null),
|
15
|
+
extensionNames.italic && React.createElement(ItalicButton, null),
|
16
|
+
extensionNames.underline && React.createElement(UnderlineButton, null),
|
17
|
+
extensionNames.nodeFormatting && React.createElement(TextAlignButtons, null))) : (React.createElement(FloatingToolbar, { className: "remirror-floating-popover" },
|
18
|
+
extensionNames.bold && React.createElement(BoldButton, null),
|
19
|
+
extensionNames.italic && React.createElement(ItalicButton, null),
|
20
|
+
extensionNames.underline && React.createElement(UnderlineButton, null)))));
|
21
|
+
};
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useCommands, useActive, useChainedCommands } from '@remirror/react';
|
3
|
+
import ToolbarButton from '../../../ui/ToolbarButton/ToolbarButton';
|
4
|
+
import FormatBoldRoundedIcon from '@mui/icons-material/FormatBoldRounded';
|
5
|
+
const BoldButton = () => {
|
6
|
+
const { toggleBold } = useCommands();
|
7
|
+
const chain = useChainedCommands();
|
8
|
+
const active = useActive();
|
9
|
+
const enabled = toggleBold.enabled();
|
10
|
+
const handleSelect = () => {
|
11
|
+
if (toggleBold.enabled()) {
|
12
|
+
chain.toggleBold().focus().run();
|
13
|
+
}
|
14
|
+
};
|
15
|
+
return (React.createElement(ToolbarButton, { handleOnClick: handleSelect, isDisabled: !enabled, isActive: active.bold(), icon: React.createElement(FormatBoldRoundedIcon, null), label: "Bold (cmd+B)" }));
|
16
|
+
};
|
17
|
+
export default BoldButton;
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useCommands, useActive, useChainedCommands } from '@remirror/react';
|
3
|
+
import ToolbarButton from '../../../ui/ToolbarButton/ToolbarButton';
|
4
|
+
import FormatItalicRoundedIcon from '@mui/icons-material/FormatItalicRounded';
|
5
|
+
const ItalicButton = () => {
|
6
|
+
const { toggleItalic } = useCommands();
|
7
|
+
const chain = useChainedCommands();
|
8
|
+
const active = useActive();
|
9
|
+
const enabled = toggleItalic.enabled();
|
10
|
+
const handleSelect = () => {
|
11
|
+
if (toggleItalic.enabled()) {
|
12
|
+
chain.toggleItalic().focus().run();
|
13
|
+
}
|
14
|
+
};
|
15
|
+
return (React.createElement(ToolbarButton, { handleOnClick: handleSelect, isDisabled: !enabled, isActive: active.italic(), icon: React.createElement(FormatItalicRoundedIcon, null), label: "Italic (cmd+I)" }));
|
16
|
+
};
|
17
|
+
export default ItalicButton;
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useCommands, useChainedCommands } from '@remirror/react';
|
3
|
+
import ToolbarButton from '../../../../ui/ToolbarButton/ToolbarButton';
|
4
|
+
import FormatAlignCenterIcon from '@mui/icons-material/FormatAlignCenter';
|
5
|
+
const CenterAlignButton = () => {
|
6
|
+
const { centerAlign } = useCommands();
|
7
|
+
const chain = useChainedCommands();
|
8
|
+
const handleSelect = () => {
|
9
|
+
if (centerAlign.enabled()) {
|
10
|
+
chain.centerAlign().focus().run();
|
11
|
+
}
|
12
|
+
};
|
13
|
+
const active = centerAlign.active?.() || false;
|
14
|
+
const enabled = centerAlign.enabled();
|
15
|
+
return (React.createElement(ToolbarButton, { handleOnClick: handleSelect, isDisabled: !enabled, isActive: active, icon: React.createElement(FormatAlignCenterIcon, null), label: "Align center" }));
|
16
|
+
};
|
17
|
+
export default CenterAlignButton;
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useCommands, useChainedCommands } from '@remirror/react';
|
3
|
+
import ToolbarButton from '../../../../ui/ToolbarButton/ToolbarButton';
|
4
|
+
import FormatAlignJustifyIcon from '@mui/icons-material/FormatAlignJustify';
|
5
|
+
const JustifyAlignButton = () => {
|
6
|
+
const { justifyAlign } = useCommands();
|
7
|
+
const chain = useChainedCommands();
|
8
|
+
const handleSelect = () => {
|
9
|
+
if (justifyAlign.enabled()) {
|
10
|
+
chain.justifyAlign().focus().run();
|
11
|
+
}
|
12
|
+
};
|
13
|
+
const active = justifyAlign.active?.() || false;
|
14
|
+
const enabled = justifyAlign.enabled();
|
15
|
+
return (React.createElement(ToolbarButton, { handleOnClick: handleSelect, isDisabled: !enabled, isActive: active, icon: React.createElement(FormatAlignJustifyIcon, null), label: "Justify" }));
|
16
|
+
};
|
17
|
+
export default JustifyAlignButton;
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useCommands, useChainedCommands } from '@remirror/react';
|
3
|
+
import ToolbarButton from '../../../../ui/ToolbarButton/ToolbarButton';
|
4
|
+
import FormatAlignLeftIcon from '@mui/icons-material/FormatAlignLeft';
|
5
|
+
const LeftAlignButton = () => {
|
6
|
+
const { leftAlign } = useCommands();
|
7
|
+
const chain = useChainedCommands();
|
8
|
+
const handleSelect = () => {
|
9
|
+
if (leftAlign.enabled()) {
|
10
|
+
chain.leftAlign().focus().run();
|
11
|
+
}
|
12
|
+
};
|
13
|
+
const active = leftAlign.active?.() || false;
|
14
|
+
const enabled = leftAlign.enabled();
|
15
|
+
return (React.createElement(ToolbarButton, { handleOnClick: handleSelect, isDisabled: !enabled, isActive: active, icon: React.createElement(FormatAlignLeftIcon, null), label: "Align left" }));
|
16
|
+
};
|
17
|
+
export default LeftAlignButton;
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useCommands, useChainedCommands } from '@remirror/react';
|
3
|
+
import ToolbarButton from '../../../../ui/ToolbarButton/ToolbarButton';
|
4
|
+
import FormatAlignRightIcon from '@mui/icons-material/FormatAlignRight';
|
5
|
+
const RightAlignButton = () => {
|
6
|
+
const { rightAlign } = useCommands();
|
7
|
+
const chain = useChainedCommands();
|
8
|
+
const handleSelect = () => {
|
9
|
+
if (rightAlign.enabled()) {
|
10
|
+
chain.rightAlign().focus().run();
|
11
|
+
}
|
12
|
+
};
|
13
|
+
const active = rightAlign.active?.() || false;
|
14
|
+
const enabled = rightAlign.enabled();
|
15
|
+
return (React.createElement(ToolbarButton, { handleOnClick: handleSelect, isDisabled: !enabled, isActive: active, icon: React.createElement(FormatAlignRightIcon, null), label: "Align right" }));
|
16
|
+
};
|
17
|
+
export default RightAlignButton;
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import LeftAlignButton from './LeftAlign/LeftAlignButton';
|
3
|
+
import CenterAlignButton from './CenterAlign/CenterAlignButton';
|
4
|
+
import RightAlignButton from './RightAlign/RightAlignButton';
|
5
|
+
import JustifyAlignButton from './JustifyAlign/JustifyAlignButton';
|
6
|
+
import { VerticalDivider } from '@remirror/react-components';
|
7
|
+
const TextAlignButtons = () => {
|
8
|
+
return (React.createElement(React.Fragment, null,
|
9
|
+
React.createElement(VerticalDivider, { className: "editor-divider" }),
|
10
|
+
React.createElement(LeftAlignButton, null),
|
11
|
+
React.createElement(CenterAlignButton, null),
|
12
|
+
React.createElement(RightAlignButton, null),
|
13
|
+
React.createElement(JustifyAlignButton, null),
|
14
|
+
React.createElement(VerticalDivider, { className: "editor-divider" })));
|
15
|
+
};
|
16
|
+
export default TextAlignButtons;
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useCommands, useActive, useChainedCommands } from '@remirror/react';
|
3
|
+
import ToolbarButton from '../../../ui/ToolbarButton/ToolbarButton';
|
4
|
+
import FormatUnderlinedRoundedIcon from '@mui/icons-material/FormatUnderlinedRounded';
|
5
|
+
const UnderlineButton = () => {
|
6
|
+
const { toggleUnderline } = useCommands();
|
7
|
+
const chain = useChainedCommands();
|
8
|
+
const active = useActive();
|
9
|
+
const enabled = toggleUnderline.enabled();
|
10
|
+
const handleSelect = () => {
|
11
|
+
if (toggleUnderline.enabled()) {
|
12
|
+
chain.toggleUnderline().focus().run();
|
13
|
+
}
|
14
|
+
};
|
15
|
+
return (React.createElement(ToolbarButton, { handleOnClick: handleSelect, isDisabled: !enabled, isActive: active.underline(), icon: React.createElement(FormatUnderlinedRoundedIcon, null), label: "Underline (cmd+U)" }));
|
16
|
+
};
|
17
|
+
export default UnderlineButton;
|
@@ -0,0 +1,7 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import Editor from './Editor/Editor';
|
3
|
+
const FormattedTextEditor = () => {
|
4
|
+
return (React.createElement("div", { className: "remirror-theme formatted-text-editor editor-wrapper" },
|
5
|
+
React.createElement(Editor, null)));
|
6
|
+
};
|
7
|
+
export default FormattedTextEditor;
|