@squiz/formatted-text-editor 1.12.0-alpha.8 → 1.12.1-alpha.0
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/.eslintrc.json +34 -0
- package/CHANGELOG.md +48 -0
- package/README.md +2 -3
- package/build.js +21 -0
- package/cypress/e2e/bold.spec.cy.ts +18 -0
- package/cypress/global.d.ts +9 -0
- package/cypress/support/commands.ts +130 -0
- package/cypress/support/e2e.ts +20 -0
- package/cypress/tsconfig.json +8 -0
- package/cypress.config.ts +7 -0
- package/demo/App.tsx +39 -0
- package/demo/index.html +13 -0
- package/demo/index.scss +40 -0
- package/demo/main.tsx +10 -0
- package/demo/public/favicon-dxp.svg +3 -0
- package/demo/vite-env.d.ts +1 -0
- package/file-transformer.js +1 -0
- package/jest.bootstrap.ts +3 -0
- package/jest.config.ts +30 -0
- package/lib/Editor/Editor.d.ts +4 -2
- package/lib/Editor/Editor.js +11 -14
- package/lib/EditorToolbar/FloatingToolbar.d.ts +1 -0
- package/lib/EditorToolbar/FloatingToolbar.js +31 -0
- package/lib/EditorToolbar/Toolbar.d.ts +1 -0
- package/lib/EditorToolbar/Toolbar.js +25 -0
- package/lib/EditorToolbar/Tools/Link/Form/LinkForm.d.ts +10 -0
- package/lib/EditorToolbar/Tools/Link/Form/LinkForm.js +23 -0
- package/lib/EditorToolbar/Tools/Link/LinkButton.d.ts +5 -0
- package/lib/EditorToolbar/Tools/Link/LinkButton.js +34 -0
- package/lib/EditorToolbar/Tools/Link/LinkModal.d.ts +8 -0
- package/lib/EditorToolbar/Tools/Link/LinkModal.js +14 -0
- package/lib/EditorToolbar/Tools/Link/RemoveLinkButton.d.ts +2 -0
- package/lib/EditorToolbar/Tools/Link/RemoveLinkButton.js +16 -0
- package/lib/EditorToolbar/Tools/Redo/RedoButton.d.ts +2 -0
- package/lib/EditorToolbar/Tools/Redo/RedoButton.js +16 -0
- package/lib/EditorToolbar/Tools/TextAlign/TextAlignButtons.js +4 -1
- package/lib/EditorToolbar/Tools/TextType/Heading/HeadingButton.d.ts +5 -0
- package/lib/EditorToolbar/Tools/TextType/Heading/HeadingButton.js +32 -0
- package/lib/EditorToolbar/Tools/TextType/Paragraph/ParagraphButton.d.ts +2 -0
- package/lib/EditorToolbar/Tools/TextType/Paragraph/ParagraphButton.js +16 -0
- package/lib/EditorToolbar/Tools/TextType/Preformatted/PreformattedButton.d.ts +2 -0
- package/lib/EditorToolbar/Tools/TextType/Preformatted/PreformattedButton.js +16 -0
- package/lib/EditorToolbar/Tools/TextType/TextTypeDropdown.d.ts +2 -0
- package/lib/EditorToolbar/Tools/TextType/TextTypeDropdown.js +35 -0
- package/lib/EditorToolbar/Tools/Undo/UndoButton.d.ts +2 -0
- package/lib/EditorToolbar/Tools/Undo/UndoButton.js +16 -0
- package/lib/EditorToolbar/index.d.ts +2 -0
- package/lib/EditorToolbar/index.js +2 -0
- package/lib/Extensions/Extensions.d.ts +4 -0
- package/lib/Extensions/Extensions.js +20 -0
- package/lib/Extensions/LinkExtension/LinkExtension.d.ts +16 -0
- package/lib/Extensions/LinkExtension/LinkExtension.js +91 -0
- package/lib/Extensions/PreformattedExtension/PreformattedExtension.d.ts +10 -0
- package/lib/Extensions/PreformattedExtension/PreformattedExtension.js +46 -0
- package/lib/FormattedTextEditor.d.ts +2 -2
- package/lib/FormattedTextEditor.js +1 -6
- package/lib/hooks/index.d.ts +1 -0
- package/lib/hooks/index.js +1 -0
- package/lib/hooks/useExtensionNames.d.ts +1 -0
- package/lib/hooks/useExtensionNames.js +12 -0
- package/lib/index.css +787 -3686
- package/lib/ui/Inputs/Select/Select.d.ts +12 -0
- package/lib/ui/Inputs/Select/Select.js +23 -0
- package/lib/ui/Inputs/Text/TextInput.d.ts +4 -0
- package/lib/ui/Inputs/Text/TextInput.js +7 -0
- package/lib/ui/Modal/FormModal.d.ts +5 -0
- package/lib/ui/Modal/FormModal.js +11 -0
- package/lib/ui/Modal/Modal.d.ts +10 -0
- package/lib/ui/Modal/Modal.js +48 -0
- package/lib/ui/ToolbarButton/ToolbarButton.d.ts +1 -1
- package/lib/ui/ToolbarButton/ToolbarButton.js +1 -1
- package/lib/ui/ToolbarDropdown/ToolbarDropdown.d.ts +6 -0
- package/lib/ui/ToolbarDropdown/ToolbarDropdown.js +20 -0
- package/lib/ui/ToolbarDropdownButton/ToolbarDropdownButton.d.ts +9 -0
- package/lib/ui/ToolbarDropdownButton/ToolbarDropdownButton.js +8 -0
- package/lib/utils/createToolbarPositioner.d.ts +18 -0
- package/lib/utils/createToolbarPositioner.js +81 -0
- package/lib/utils/getCursorRect.d.ts +2 -0
- package/lib/utils/getCursorRect.js +3 -0
- package/package.json +22 -13
- package/postcss.config.js +12 -0
- package/src/Editor/Editor.mock.tsx +43 -0
- package/src/Editor/Editor.spec.tsx +254 -0
- package/src/Editor/Editor.tsx +46 -0
- package/src/Editor/_editor.scss +82 -0
- package/src/EditorToolbar/FloatingToolbar.spec.tsx +30 -0
- package/src/EditorToolbar/FloatingToolbar.tsx +40 -0
- package/src/EditorToolbar/Toolbar.tsx +33 -0
- package/src/EditorToolbar/Tools/Bold/BoldButton.spec.tsx +19 -0
- package/src/EditorToolbar/Tools/Bold/BoldButton.tsx +30 -0
- package/src/EditorToolbar/Tools/Italic/ItalicButton.spec.tsx +19 -0
- package/src/EditorToolbar/Tools/Italic/ItalicButton.tsx +30 -0
- package/src/EditorToolbar/Tools/Link/Form/LinkForm.spec.tsx +30 -0
- package/src/EditorToolbar/Tools/Link/Form/LinkForm.tsx +48 -0
- package/src/EditorToolbar/Tools/Link/LinkButton.spec.tsx +277 -0
- package/src/EditorToolbar/Tools/Link/LinkButton.tsx +56 -0
- package/src/EditorToolbar/Tools/Link/LinkModal.tsx +29 -0
- package/src/EditorToolbar/Tools/Link/RemoveLinkButton.spec.tsx +46 -0
- package/src/EditorToolbar/Tools/Link/RemoveLinkButton.tsx +27 -0
- package/src/EditorToolbar/Tools/Redo/RedoButton.spec.tsx +59 -0
- package/src/EditorToolbar/Tools/Redo/RedoButton.tsx +30 -0
- package/src/EditorToolbar/Tools/TextAlign/CenterAlign/CenterAlignButton.spec.tsx +39 -0
- package/src/EditorToolbar/Tools/TextAlign/CenterAlign/CenterAlignButton.tsx +31 -0
- package/src/EditorToolbar/Tools/TextAlign/JustifyAlign/JustifyAlignButton.spec.tsx +39 -0
- package/src/EditorToolbar/Tools/TextAlign/JustifyAlign/JustifyAlignButton.tsx +31 -0
- package/src/EditorToolbar/Tools/TextAlign/LeftAlign/LeftAlignButton.spec.tsx +39 -0
- package/src/EditorToolbar/Tools/TextAlign/LeftAlign/LeftAlignButton.tsx +31 -0
- package/src/EditorToolbar/Tools/TextAlign/RightAlign/RightAlignButton.spec.tsx +39 -0
- package/src/EditorToolbar/Tools/TextAlign/RightAlign/RightAlignButton.tsx +31 -0
- package/src/EditorToolbar/Tools/TextAlign/TextAlignButtons.tsx +21 -0
- package/src/EditorToolbar/Tools/TextType/Heading/HeadingButton.spec.tsx +56 -0
- package/src/EditorToolbar/Tools/TextType/Heading/HeadingButton.tsx +52 -0
- package/src/EditorToolbar/Tools/TextType/Paragraph/ParagraphButton.spec.tsx +30 -0
- package/src/EditorToolbar/Tools/TextType/Paragraph/ParagraphButton.tsx +25 -0
- package/src/EditorToolbar/Tools/TextType/Preformatted/PreformattedButton.spec.tsx +47 -0
- package/src/EditorToolbar/Tools/TextType/Preformatted/PreformattedButton.tsx +30 -0
- package/src/EditorToolbar/Tools/TextType/TextTypeDropdown.spec.tsx +51 -0
- package/src/EditorToolbar/Tools/TextType/TextTypeDropdown.tsx +44 -0
- package/src/EditorToolbar/Tools/Underline/Underline.spec.tsx +19 -0
- package/src/EditorToolbar/Tools/Underline/UnderlineButton.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/_floating-toolbar.scss +4 -0
- package/src/EditorToolbar/_toolbar.scss +16 -0
- package/src/EditorToolbar/index.ts +2 -0
- package/src/Extensions/Extensions.ts +29 -0
- package/src/Extensions/LinkExtension/LinkExtension.ts +116 -0
- package/src/Extensions/PreformattedExtension/PreformattedExtension.ts +50 -0
- package/src/FormattedTextEditor.spec.tsx +10 -0
- package/src/FormattedTextEditor.tsx +3 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useExtensionNames.ts +15 -0
- package/src/index.scss +19 -0
- package/src/index.ts +3 -0
- package/src/ui/Inputs/Select/Select.spec.tsx +30 -0
- package/src/ui/Inputs/Select/Select.tsx +66 -0
- package/src/ui/Inputs/Text/TextInput.spec.tsx +43 -0
- package/src/ui/Inputs/Text/TextInput.tsx +20 -0
- package/src/ui/Modal/FormModal.spec.tsx +20 -0
- package/src/ui/Modal/FormModal.tsx +17 -0
- package/src/ui/Modal/Modal.spec.tsx +113 -0
- package/src/ui/Modal/Modal.tsx +97 -0
- package/src/ui/Modal/_modal.scss +24 -0
- package/src/ui/ToolbarButton/ToolbarButton.tsx +26 -0
- package/src/ui/ToolbarButton/_toolbar-button.scss +17 -0
- package/src/ui/ToolbarDropdown/ToolbarDropdown.spec.tsx +78 -0
- package/src/ui/ToolbarDropdown/ToolbarDropdown.tsx +42 -0
- package/src/ui/ToolbarDropdown/_toolbar-dropdown.scss +32 -0
- package/src/ui/ToolbarDropdownButton/ToolbarDropdownButton.spec.tsx +48 -0
- package/src/ui/ToolbarDropdownButton/ToolbarDropdownButton.tsx +29 -0
- package/src/ui/ToolbarDropdownButton/_toolbar-dropdown-button.scss +14 -0
- package/src/ui/_buttons.scss +19 -0
- package/src/ui/_forms.scss +16 -0
- package/src/utils/createToolbarPositioner.ts +115 -0
- package/src/utils/getCursorRect.ts +5 -0
- package/tailwind.config.cjs +83 -0
- package/tests/index.ts +2 -0
- package/tests/renderWithEditor.tsx +110 -0
- package/tests/select.tsx +16 -0
- package/tsconfig.json +22 -0
- package/vite.config.ts +19 -0
- package/lib/EditorToolbar/EditorToolbar.d.ts +0 -7
- package/lib/EditorToolbar/EditorToolbar.js +0 -22
@@ -0,0 +1,34 @@
|
|
1
|
+
import React, { useCallback, useState } from 'react';
|
2
|
+
import InsertLinkRoundedIcon from '@mui/icons-material/InsertLinkRounded';
|
3
|
+
import LinkModal from './LinkModal';
|
4
|
+
import ToolbarButton from '../../../ui/ToolbarButton/ToolbarButton';
|
5
|
+
import { useActive, useCommands, useExtensionEvent } from '@remirror/react';
|
6
|
+
import { LinkExtension } from '../../../Extensions/LinkExtension/LinkExtension';
|
7
|
+
const LinkButton = ({ inPopover = false }) => {
|
8
|
+
const [showModal, setShowModal] = useState(false);
|
9
|
+
const { selectLink, updateLink } = useCommands();
|
10
|
+
const active = useActive();
|
11
|
+
const handleClick = () => {
|
12
|
+
if (!showModal) {
|
13
|
+
selectLink();
|
14
|
+
// form element are uncontrolled, let the event loop run to
|
15
|
+
// update the selected text in state before showing the modal.
|
16
|
+
requestAnimationFrame(() => {
|
17
|
+
setShowModal(true);
|
18
|
+
});
|
19
|
+
}
|
20
|
+
};
|
21
|
+
const handleSubmit = (data) => {
|
22
|
+
updateLink(data);
|
23
|
+
setShowModal(false);
|
24
|
+
};
|
25
|
+
if (!inPopover) {
|
26
|
+
// when Ctrl+K is pressed show the modal, only registered in the toolbar button instance to avoid the key press
|
27
|
+
// being double handled.
|
28
|
+
useExtensionEvent(LinkExtension, 'onShortcut', useCallback(() => handleClick(), []));
|
29
|
+
}
|
30
|
+
return (React.createElement(React.Fragment, null,
|
31
|
+
React.createElement(ToolbarButton, { handleOnClick: handleClick, isActive: active.link(), icon: React.createElement(InsertLinkRoundedIcon, null), label: "Link (cmd+K)" }),
|
32
|
+
showModal && React.createElement(LinkModal, { onCancel: () => setShowModal(false), onSubmit: handleSubmit })));
|
33
|
+
};
|
34
|
+
export default LinkButton;
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import { LinkFormData } from './Form/LinkForm';
|
2
|
+
import { SubmitHandler } from 'react-hook-form';
|
3
|
+
type LinkModalProps = {
|
4
|
+
onCancel: () => void;
|
5
|
+
onSubmit: SubmitHandler<LinkFormData>;
|
6
|
+
};
|
7
|
+
declare const LinkModal: ({ onCancel, onSubmit }: LinkModalProps) => JSX.Element;
|
8
|
+
export default LinkModal;
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import { getMarkRanges } from 'remirror';
|
2
|
+
import LinkForm from './Form/LinkForm';
|
3
|
+
import React from 'react';
|
4
|
+
import { useRemirrorContext, useCurrentSelection } from '@remirror/react';
|
5
|
+
import FormModal from '../../../ui/Modal/FormModal';
|
6
|
+
const LinkModal = ({ onCancel, onSubmit }) => {
|
7
|
+
const { helpers, view: { state }, } = useRemirrorContext();
|
8
|
+
const selection = useCurrentSelection();
|
9
|
+
const currentLink = getMarkRanges(selection, 'link')[0];
|
10
|
+
const selectedText = helpers.getTextBetween(selection.from, selection.to, state.doc);
|
11
|
+
return (React.createElement(FormModal, { title: "Link", onCancel: onCancel },
|
12
|
+
React.createElement(LinkForm, { data: { ...currentLink?.mark.attrs, text: selectedText }, onSubmit: onSubmit })));
|
13
|
+
};
|
14
|
+
export default LinkModal;
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useRemirrorContext, useChainedCommands } from '@remirror/react';
|
3
|
+
import ToolbarButton from '../../../ui/ToolbarButton/ToolbarButton';
|
4
|
+
import LinkOffIcon from '@mui/icons-material/LinkOff';
|
5
|
+
const RemoveLinkButton = () => {
|
6
|
+
const { commands } = useRemirrorContext({ autoUpdate: true });
|
7
|
+
const chain = useChainedCommands();
|
8
|
+
const enabled = commands.removeLink.enabled();
|
9
|
+
const handleClick = () => {
|
10
|
+
if (enabled) {
|
11
|
+
chain.removeLink().focus().run();
|
12
|
+
}
|
13
|
+
};
|
14
|
+
return (React.createElement(ToolbarButton, { handleOnClick: handleClick, isActive: false, isDisabled: !enabled, icon: React.createElement(LinkOffIcon, null), label: "Remove link" }));
|
15
|
+
};
|
16
|
+
export default RemoveLinkButton;
|
@@ -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;
|
@@ -3,11 +3,14 @@ import LeftAlignButton from './LeftAlign/LeftAlignButton';
|
|
3
3
|
import CenterAlignButton from './CenterAlign/CenterAlignButton';
|
4
4
|
import RightAlignButton from './RightAlign/RightAlignButton';
|
5
5
|
import JustifyAlignButton from './JustifyAlign/JustifyAlignButton';
|
6
|
+
import { VerticalDivider } from '@remirror/react-components';
|
6
7
|
const TextAlignButtons = () => {
|
7
8
|
return (React.createElement(React.Fragment, null,
|
9
|
+
React.createElement(VerticalDivider, { className: "editor-divider" }),
|
8
10
|
React.createElement(LeftAlignButton, null),
|
9
11
|
React.createElement(CenterAlignButton, null),
|
10
12
|
React.createElement(RightAlignButton, null),
|
11
|
-
React.createElement(JustifyAlignButton, null)
|
13
|
+
React.createElement(JustifyAlignButton, null),
|
14
|
+
React.createElement(VerticalDivider, { className: "editor-divider" })));
|
12
15
|
};
|
13
16
|
export default TextAlignButtons;
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useCommands, useChainedCommands, useActive } from '@remirror/react';
|
3
|
+
import DropdownButton from '../../../../ui/ToolbarDropdownButton/ToolbarDropdownButton';
|
4
|
+
const HeadingButton = ({ level }) => {
|
5
|
+
const { toggleHeading } = useCommands();
|
6
|
+
const chain = useChainedCommands();
|
7
|
+
const active = useActive();
|
8
|
+
const enabled = toggleHeading.enabled({ level });
|
9
|
+
const handleSelect = () => {
|
10
|
+
if (toggleHeading.enabled({ level })) {
|
11
|
+
chain.toggleHeading({ level }).focus().run();
|
12
|
+
}
|
13
|
+
};
|
14
|
+
const headingContent = () => {
|
15
|
+
switch (level) {
|
16
|
+
case 1:
|
17
|
+
return React.createElement("h1", null, "Heading 1");
|
18
|
+
case 2:
|
19
|
+
return React.createElement("h2", null, "Heading 2");
|
20
|
+
case 3:
|
21
|
+
return React.createElement("h3", null, "Heading 3");
|
22
|
+
case 4:
|
23
|
+
return React.createElement("h4", null, "Heading 4");
|
24
|
+
case 5:
|
25
|
+
return React.createElement("h5", null, "Heading 5");
|
26
|
+
case 6:
|
27
|
+
return React.createElement("h6", null, "Heading 6");
|
28
|
+
}
|
29
|
+
};
|
30
|
+
return (React.createElement(DropdownButton, { handleOnClick: handleSelect, isDisabled: !enabled, isActive: active.heading({ level }), label: `Heading ${level}` }, headingContent()));
|
31
|
+
};
|
32
|
+
export default HeadingButton;
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useCommands, useChainedCommands, useActive } from '@remirror/react';
|
3
|
+
import DropdownButton from '../../../../ui/ToolbarDropdownButton/ToolbarDropdownButton';
|
4
|
+
const ParagraphButton = () => {
|
5
|
+
const { convertParagraph } = useCommands();
|
6
|
+
const chain = useChainedCommands();
|
7
|
+
const active = useActive();
|
8
|
+
const handleSelect = () => {
|
9
|
+
if (convertParagraph.enabled()) {
|
10
|
+
chain.convertParagraph().focus().run();
|
11
|
+
}
|
12
|
+
};
|
13
|
+
return (React.createElement(DropdownButton, { handleOnClick: handleSelect, isDisabled: false, isActive: active.paragraph(), label: "Paragraph" },
|
14
|
+
React.createElement("p", null, "Paragraph")));
|
15
|
+
};
|
16
|
+
export default ParagraphButton;
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useCommands, useActive } from '@remirror/react';
|
3
|
+
import DropdownButton from '../../../../ui/ToolbarDropdownButton/ToolbarDropdownButton';
|
4
|
+
const PreformattedButton = () => {
|
5
|
+
const { togglePreformatted } = useCommands();
|
6
|
+
const active = useActive();
|
7
|
+
const enabled = togglePreformatted.enabled();
|
8
|
+
const handleSelect = () => {
|
9
|
+
if (togglePreformatted.enabled()) {
|
10
|
+
togglePreformatted();
|
11
|
+
}
|
12
|
+
};
|
13
|
+
return (React.createElement(DropdownButton, { handleOnClick: handleSelect, isDisabled: !enabled, isActive: active.preformatted(), label: "Preformatted" },
|
14
|
+
React.createElement("pre", null, "Preformatted")));
|
15
|
+
};
|
16
|
+
export default PreformattedButton;
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import HeadingButton from './Heading/HeadingButton';
|
3
|
+
import ParagraphButton from './Paragraph/ParagraphButton';
|
4
|
+
import PreformattedButton from './Preformatted/PreformattedButton';
|
5
|
+
import ToolbarDropdown from '../../../ui/ToolbarDropdown/ToolbarDropdown';
|
6
|
+
import { useActive, VerticalDivider } from '@remirror/react';
|
7
|
+
const TextTypeDropdown = () => {
|
8
|
+
const active = useActive();
|
9
|
+
const activeLabel = () => {
|
10
|
+
// Determine if preformatted is active
|
11
|
+
if (active.preformatted()) {
|
12
|
+
return 'Preformatted';
|
13
|
+
}
|
14
|
+
// Determine if a heading is active
|
15
|
+
for (let i = 1; i <= 6; i++) {
|
16
|
+
if (active.heading({ level: i })) {
|
17
|
+
return `Heading ${i}`;
|
18
|
+
}
|
19
|
+
}
|
20
|
+
// Default to paragraph
|
21
|
+
return 'Paragraph';
|
22
|
+
};
|
23
|
+
return (React.createElement(React.Fragment, null,
|
24
|
+
React.createElement(ToolbarDropdown, { label: activeLabel() },
|
25
|
+
React.createElement(ParagraphButton, null),
|
26
|
+
React.createElement(HeadingButton, { level: 1 }),
|
27
|
+
React.createElement(HeadingButton, { level: 2 }),
|
28
|
+
React.createElement(HeadingButton, { level: 3 }),
|
29
|
+
React.createElement(HeadingButton, { level: 4 }),
|
30
|
+
React.createElement(HeadingButton, { level: 5 }),
|
31
|
+
React.createElement(HeadingButton, { level: 6 }),
|
32
|
+
React.createElement(PreformattedButton, null)),
|
33
|
+
React.createElement(VerticalDivider, { className: "editor-divider" })));
|
34
|
+
};
|
35
|
+
export default TextTypeDropdown;
|
@@ -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;
|
@@ -0,0 +1,4 @@
|
|
1
|
+
import { BoldExtension, HeadingExtension, ItalicExtension, NodeFormattingExtension, ParagraphExtension, UnderlineExtension, HistoryExtension } from 'remirror/extensions';
|
2
|
+
import { PreformattedExtension } from './PreformattedExtension/PreformattedExtension';
|
3
|
+
import { LinkExtension } from './LinkExtension/LinkExtension';
|
4
|
+
export declare const Extensions: () => (BoldExtension | HistoryExtension | HeadingExtension | ItalicExtension | NodeFormattingExtension | ParagraphExtension | UnderlineExtension | LinkExtension | PreformattedExtension)[];
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { BoldExtension, HeadingExtension, ItalicExtension, NodeFormattingExtension, ParagraphExtension, UnderlineExtension, HistoryExtension, } from 'remirror/extensions';
|
2
|
+
import { PreformattedExtension } from './PreformattedExtension/PreformattedExtension';
|
3
|
+
import { LinkExtension } from './LinkExtension/LinkExtension';
|
4
|
+
export const Extensions = () => [
|
5
|
+
new BoldExtension(),
|
6
|
+
new HeadingExtension(),
|
7
|
+
new ItalicExtension(),
|
8
|
+
new NodeFormattingExtension(),
|
9
|
+
new ParagraphExtension(),
|
10
|
+
new PreformattedExtension(),
|
11
|
+
new UnderlineExtension(),
|
12
|
+
new HistoryExtension(),
|
13
|
+
new LinkExtension({
|
14
|
+
supportedTargets: [
|
15
|
+
// '_self' is the browser default and will be used when encountering a link with a
|
16
|
+
// different target is encountered.
|
17
|
+
'_blank',
|
18
|
+
],
|
19
|
+
}),
|
20
|
+
];
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import { ApplySchemaAttributes, MarkExtensionSpec, MarkSpecOverride } from 'remirror';
|
2
|
+
import { KeyBindingProps } from '@remirror/core';
|
3
|
+
import { CommandFunction } from '@remirror/pm';
|
4
|
+
import { LinkAttributes as RemirrorLinkAttributes, LinkExtension as RemirrorLinkExtension } from 'remirror/extensions';
|
5
|
+
export type UpdateLinkOptions = LinkAttributes & {
|
6
|
+
text: string;
|
7
|
+
};
|
8
|
+
export type LinkAttributes = RemirrorLinkAttributes & {
|
9
|
+
title?: string;
|
10
|
+
};
|
11
|
+
export declare class LinkExtension extends RemirrorLinkExtension {
|
12
|
+
createMarkSpec(extra: ApplySchemaAttributes, override: MarkSpecOverride): MarkExtensionSpec;
|
13
|
+
shortcut({ tr }: KeyBindingProps): boolean;
|
14
|
+
selectLink(): CommandFunction;
|
15
|
+
updateLink(options: UpdateLinkOptions): CommandFunction;
|
16
|
+
}
|
@@ -0,0 +1,91 @@
|
|
1
|
+
import { getMarkRanges, isElementDomNode } from 'remirror';
|
2
|
+
import { getTextSelection, getMarkRange, updateMark, removeMark } from '@remirror/core';
|
3
|
+
import { LinkExtension as RemirrorLinkExtension } from 'remirror/extensions';
|
4
|
+
export class LinkExtension extends RemirrorLinkExtension {
|
5
|
+
createMarkSpec(extra, override) {
|
6
|
+
const spec = super.createMarkSpec(extra, override);
|
7
|
+
return {
|
8
|
+
...spec,
|
9
|
+
excludes: undefined,
|
10
|
+
attrs: {
|
11
|
+
...spec.attrs,
|
12
|
+
title: { default: undefined },
|
13
|
+
},
|
14
|
+
parseDOM: [
|
15
|
+
{
|
16
|
+
tag: 'a[href]',
|
17
|
+
getAttrs: (node) => {
|
18
|
+
if (!isElementDomNode(node)) {
|
19
|
+
return false;
|
20
|
+
}
|
21
|
+
return {
|
22
|
+
...extra.parse(node),
|
23
|
+
auto: false,
|
24
|
+
href: node.getAttribute('href'),
|
25
|
+
target: node.getAttribute('target'),
|
26
|
+
title: node.getAttribute('title'),
|
27
|
+
};
|
28
|
+
},
|
29
|
+
},
|
30
|
+
],
|
31
|
+
};
|
32
|
+
}
|
33
|
+
shortcut({ tr }) {
|
34
|
+
// override parent implementation to allow a link to be inserted without requiring a text selection first.
|
35
|
+
const { from, to, $from } = tr.selection;
|
36
|
+
const mark = getMarkRange($from, this.type);
|
37
|
+
const selectedText = tr.doc.textBetween(from, to);
|
38
|
+
this.options.onShortcut({
|
39
|
+
activeLink: mark ? { attrs: mark.mark.attrs, from: mark.from, to: mark.to } : undefined,
|
40
|
+
selectedText,
|
41
|
+
from,
|
42
|
+
to,
|
43
|
+
});
|
44
|
+
return true;
|
45
|
+
}
|
46
|
+
selectLink() {
|
47
|
+
// parent implementation selects only the link text, this mimics closer to Google Docs where
|
48
|
+
// the select text is widened to include the link but retains non-link selected text as well.
|
49
|
+
return (props) => {
|
50
|
+
const { tr } = props;
|
51
|
+
const ranges = getMarkRanges(tr.selection, this.type);
|
52
|
+
if (ranges.length === 0) {
|
53
|
+
return false;
|
54
|
+
}
|
55
|
+
// work out the start position of the first link and end position of the last link in the selection.
|
56
|
+
const from = Math.min(tr.selection.from, ...ranges.map((range) => range.from));
|
57
|
+
const to = Math.max(tr.selection.to, ...ranges.map((range) => range.to));
|
58
|
+
// don't need to widen the selection, return early.
|
59
|
+
if (tr.selection.from === from && tr.selection.to === to) {
|
60
|
+
return false;
|
61
|
+
}
|
62
|
+
// widen the selection to make sure the full link is included.
|
63
|
+
this.store.commands.selectText.original({ from, to })(props);
|
64
|
+
return true;
|
65
|
+
};
|
66
|
+
}
|
67
|
+
updateLink(options) {
|
68
|
+
const { text, ...attrs } = options;
|
69
|
+
return (props) => {
|
70
|
+
const { tr, dispatch, view } = props;
|
71
|
+
const range = { from: tr.selection.from, to: tr.selection.to };
|
72
|
+
const selectedText = tr.doc.textBetween(range.from, range.to);
|
73
|
+
if (text !== selectedText) {
|
74
|
+
// update the text in the editor if it was updated, update the range to cover the length of the new text.
|
75
|
+
dispatch?.(tr.insertText(text));
|
76
|
+
range.to = range.from + text.length;
|
77
|
+
}
|
78
|
+
// apply the link, or remove it if no URL was provided.
|
79
|
+
if (attrs.href.length > 0) {
|
80
|
+
updateMark({ type: this.type, attrs, range })(props);
|
81
|
+
}
|
82
|
+
else {
|
83
|
+
removeMark({ type: this.type, range })(props);
|
84
|
+
}
|
85
|
+
// move the cursor to the end of the link and re-focus the editor.
|
86
|
+
dispatch?.(tr.setSelection(getTextSelection({ from: range.to, to: range.to }, tr.doc)));
|
87
|
+
view?.focus();
|
88
|
+
return true;
|
89
|
+
};
|
90
|
+
}
|
91
|
+
}
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import { ApplySchemaAttributes, CommandFunction, NodeExtension, NodeExtensionSpec, NodeSpecOverride } from '@remirror/core';
|
2
|
+
export declare class PreformattedExtension extends NodeExtension {
|
3
|
+
get name(): "preformatted";
|
4
|
+
createTags(): ("formattingNode" | "block" | "textBlock")[];
|
5
|
+
createNodeSpec(extra: ApplySchemaAttributes, override: NodeSpecOverride): NodeExtensionSpec;
|
6
|
+
/**
|
7
|
+
* Toggle the <pre> for the current block.
|
8
|
+
*/
|
9
|
+
togglePreformatted(): CommandFunction;
|
10
|
+
}
|
@@ -0,0 +1,46 @@
|
|
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,2 +1,2 @@
|
|
1
|
-
|
2
|
-
export default
|
1
|
+
import Editor from './Editor/Editor';
|
2
|
+
export default Editor;
|
@@ -1,7 +1,2 @@
|
|
1
|
-
import React from 'react';
|
2
1
|
import Editor from './Editor/Editor';
|
3
|
-
|
4
|
-
return (React.createElement("div", { className: "remirror-theme formatted-text-editor editor-wrapper" },
|
5
|
-
React.createElement(Editor, null)));
|
6
|
-
};
|
7
|
-
export default FormattedTextEditor;
|
2
|
+
export default Editor;
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './useExtensionNames';
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './useExtensionNames';
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const useExtensionNames: () => Record<string, true>;
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { useRemirrorContext } from '@remirror/react';
|
2
|
+
import { useMemo } from 'react';
|
3
|
+
export const useExtensionNames = () => {
|
4
|
+
const { manager } = useRemirrorContext();
|
5
|
+
return useMemo(() => {
|
6
|
+
const extensionNames = {};
|
7
|
+
manager.extensions.forEach((extension) => {
|
8
|
+
extensionNames[extension.name] = true;
|
9
|
+
});
|
10
|
+
return extensionNames;
|
11
|
+
}, [manager]);
|
12
|
+
};
|