@squiz/formatted-text-editor 1.16.0 → 1.21.1-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/.eslintrc.json +7 -0
- package/README.md +10 -0
- package/demo/App.tsx +18 -4
- package/demo/index.scss +16 -10
- package/jest.config.ts +8 -9
- package/lib/Editor/Editor.js +18 -13
- package/lib/EditorToolbar/FloatingToolbar.js +50 -20
- package/lib/EditorToolbar/Toolbar.js +33 -24
- package/lib/EditorToolbar/Tools/Bold/BoldButton.js +14 -9
- package/lib/EditorToolbar/Tools/Image/Form/ImageForm.d.ts +17 -0
- package/lib/EditorToolbar/Tools/Image/Form/ImageForm.js +84 -0
- package/lib/EditorToolbar/Tools/Image/ImageButton.d.ts +2 -0
- package/lib/EditorToolbar/Tools/Image/ImageButton.js +67 -0
- package/lib/EditorToolbar/Tools/Image/ImageModal.d.ts +8 -0
- package/lib/EditorToolbar/Tools/Image/ImageModal.js +19 -0
- package/lib/EditorToolbar/Tools/Italic/ItalicButton.js +14 -9
- package/lib/EditorToolbar/Tools/Link/Form/LinkForm.js +20 -15
- package/lib/EditorToolbar/Tools/Link/LinkButton.js +42 -14
- package/lib/EditorToolbar/Tools/Link/LinkModal.js +16 -11
- package/lib/EditorToolbar/Tools/Link/RemoveLinkButton.js +13 -8
- package/lib/EditorToolbar/Tools/Redo/RedoButton.js +13 -8
- package/lib/EditorToolbar/Tools/TextAlign/CenterAlign/CenterAlignButton.js +13 -8
- package/lib/EditorToolbar/Tools/TextAlign/JustifyAlign/JustifyAlignButton.js +13 -8
- package/lib/EditorToolbar/Tools/TextAlign/LeftAlign/LeftAlignButton.js +13 -8
- package/lib/EditorToolbar/Tools/TextAlign/RightAlign/RightAlignButton.js +13 -8
- package/lib/EditorToolbar/Tools/TextAlign/TextAlignButtons.js +19 -14
- package/lib/EditorToolbar/Tools/TextType/Heading/HeadingButton.js +19 -14
- package/lib/EditorToolbar/Tools/TextType/Paragraph/ParagraphButton.js +14 -9
- package/lib/EditorToolbar/Tools/TextType/Preformatted/PreformattedButton.js +13 -8
- package/lib/EditorToolbar/Tools/TextType/TextTypeDropdown.js +24 -19
- package/lib/EditorToolbar/Tools/Underline/UnderlineButton.js +14 -9
- package/lib/EditorToolbar/Tools/Undo/UndoButton.js +13 -8
- package/lib/EditorToolbar/index.js +18 -2
- package/lib/Extensions/Extensions.d.ts +2 -4
- package/lib/Extensions/Extensions.js +19 -13
- package/lib/Extensions/ImageExtension/ImageExtension.d.ts +3 -0
- package/lib/Extensions/ImageExtension/ImageExtension.js +7 -0
- package/lib/Extensions/LinkExtension/LinkExtension.js +17 -11
- package/lib/Extensions/PreformattedExtension/PreformattedExtension.d.ts +1 -1
- package/lib/Extensions/PreformattedExtension/PreformattedExtension.js +10 -7
- package/lib/FormattedTextEditor.js +7 -2
- package/lib/hooks/index.js +17 -1
- package/lib/hooks/useExtensionNames.js +9 -5
- package/lib/index.css +133 -76
- package/lib/index.d.ts +3 -1
- package/lib/index.js +12 -2
- package/lib/ui/Button/Button.d.ts +11 -0
- package/lib/ui/Button/Button.js +14 -0
- package/lib/ui/Fields/Input/Input.d.ts +4 -0
- package/lib/ui/Fields/Input/Input.js +33 -0
- package/lib/ui/Fields/Select/Select.js +53 -0
- package/lib/ui/Modal/FormModal.js +33 -5
- package/lib/ui/Modal/Modal.js +50 -22
- package/lib/ui/ToolbarDropdown/ToolbarDropdown.js +38 -10
- package/lib/ui/ToolbarDropdownButton/ToolbarDropdownButton.js +11 -6
- package/lib/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.d.ts +10 -0
- package/lib/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.js +160 -0
- package/lib/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.d.ts +9 -0
- package/lib/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.js +105 -0
- package/lib/utils/converters/validNodeTypes.d.ts +2 -0
- package/lib/utils/converters/validNodeTypes.js +21 -0
- package/lib/utils/createToolbarPositioner.js +16 -12
- package/lib/utils/getCursorRect.js +5 -1
- package/package.json +7 -3
- package/src/Editor/_editor.scss +2 -49
- package/src/EditorToolbar/FloatingToolbar.tsx +1 -1
- package/src/EditorToolbar/Toolbar.tsx +2 -0
- package/src/EditorToolbar/Tools/Bold/BoldButton.spec.tsx +1 -1
- package/src/EditorToolbar/Tools/Bold/BoldButton.tsx +2 -2
- package/src/EditorToolbar/Tools/Image/Form/ImageForm.spec.tsx +23 -0
- package/src/EditorToolbar/Tools/Image/Form/ImageForm.tsx +92 -0
- package/src/EditorToolbar/Tools/Image/ImageButton.spec.tsx +79 -0
- package/src/EditorToolbar/Tools/Image/ImageButton.tsx +57 -0
- package/src/EditorToolbar/Tools/Image/ImageModal.spec.tsx +83 -0
- package/src/EditorToolbar/Tools/Image/ImageModal.tsx +29 -0
- package/src/EditorToolbar/Tools/Italic/ItalicButton.spec.tsx +1 -1
- package/src/EditorToolbar/Tools/Italic/ItalicButton.tsx +2 -2
- package/src/EditorToolbar/Tools/Link/Form/LinkForm.tsx +5 -5
- package/src/EditorToolbar/Tools/Link/LinkButton.tsx +2 -2
- package/src/EditorToolbar/Tools/Link/RemoveLinkButton.tsx +2 -2
- package/src/EditorToolbar/Tools/Redo/RedoButton.tsx +2 -2
- package/src/EditorToolbar/Tools/TextAlign/CenterAlign/CenterAlignButton.tsx +2 -2
- package/src/EditorToolbar/Tools/TextAlign/JustifyAlign/JustifyAlignButton.tsx +2 -2
- package/src/EditorToolbar/Tools/TextAlign/LeftAlign/LeftAlignButton.tsx +2 -2
- package/src/EditorToolbar/Tools/TextAlign/RightAlign/RightAlignButton.tsx +2 -2
- package/src/EditorToolbar/Tools/Underline/Underline.spec.tsx +1 -1
- package/src/EditorToolbar/Tools/Underline/UnderlineButton.tsx +2 -2
- package/src/EditorToolbar/Tools/Undo/UndoButton.tsx +2 -2
- package/src/EditorToolbar/_floating-toolbar.scss +6 -0
- package/src/EditorToolbar/_toolbar.scss +8 -2
- package/src/Extensions/Extensions.ts +5 -2
- package/src/Extensions/ImageExtension/ImageExtension.ts +3 -0
- package/src/Extensions/LinkExtension/LinkExtension.ts +8 -5
- package/src/index.scss +2 -2
- package/src/index.ts +3 -1
- package/src/ui/Button/Button.spec.tsx +44 -0
- package/src/ui/Button/Button.tsx +31 -0
- package/src/ui/{_buttons.scss → Button/_button.scss} +19 -1
- package/src/ui/{Inputs/Text/TextInput.spec.tsx → Fields/Input/Input.spec.tsx} +8 -8
- package/src/ui/{Inputs/Text/TextInput.tsx → Fields/Input/Input.tsx} +4 -4
- package/src/ui/Modal/Modal.tsx +1 -0
- package/src/ui/ToolbarDropdown/ToolbarDropdown.spec.tsx +4 -2
- package/src/ui/ToolbarDropdown/ToolbarDropdown.tsx +1 -1
- package/src/ui/_typography.scss +46 -0
- package/src/utils/converters/mocks/squizNodeJson.mock.ts +75 -0
- package/src/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.spec.ts +445 -0
- package/src/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.ts +191 -0
- package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.spec.ts +307 -0
- package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.ts +123 -0
- package/src/utils/converters/validNodeTypes.spec.ts +33 -0
- package/src/utils/converters/validNodeTypes.ts +21 -0
- package/tests/renderWithEditor.tsx +2 -2
- package/tsconfig.json +1 -1
- package/lib/ui/Inputs/Select/Select.js +0 -23
- package/lib/ui/Inputs/Text/TextInput.d.ts +0 -4
- package/lib/ui/Inputs/Text/TextInput.js +0 -7
- package/lib/ui/ToolbarButton/ToolbarButton.d.ts +0 -10
- package/lib/ui/ToolbarButton/ToolbarButton.js +0 -5
- package/src/ui/ToolbarButton/ToolbarButton.tsx +0 -26
- package/src/ui/ToolbarButton/_toolbar-button.scss +0 -17
- /package/lib/ui/{Inputs → Fields}/Select/Select.d.ts +0 -0
- /package/src/ui/{Inputs → Fields}/Select/Select.spec.tsx +0 -0
- /package/src/ui/{Inputs → Fields}/Select/Select.tsx +0 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
+
}) : function(o, v) {
|
16
|
+
o["default"] = v;
|
17
|
+
});
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
19
|
+
if (mod && mod.__esModule) return mod;
|
20
|
+
var result = {};
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
22
|
+
__setModuleDefault(result, mod);
|
23
|
+
return result;
|
24
|
+
};
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
27
|
+
};
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
29
|
+
exports.Select = void 0;
|
30
|
+
const react_1 = require("@headlessui/react");
|
31
|
+
const react_2 = __importStar(require("react"));
|
32
|
+
const clsx_1 = __importDefault(require("clsx"));
|
33
|
+
const ExpandMoreRounded_1 = __importDefault(require("@mui/icons-material/ExpandMoreRounded"));
|
34
|
+
const ExpandLessRounded_1 = __importDefault(require("@mui/icons-material/ExpandLessRounded"));
|
35
|
+
const Select = ({ name, label, value, onChange, options }) => {
|
36
|
+
const [selectedOption, setSelectedOptions] = (0, react_2.useState)(value ? options[value] : null);
|
37
|
+
const handleChange = (value) => {
|
38
|
+
setSelectedOptions(options[value]);
|
39
|
+
onChange?.(value);
|
40
|
+
};
|
41
|
+
return (react_2.default.createElement(react_1.Listbox, { value: value, name: name, "aria-labelledby": name, onChange: handleChange }, ({ open }) => (react_2.default.createElement(react_2.default.Fragment, null,
|
42
|
+
label && react_2.default.createElement(react_1.Listbox.Label, { className: "squiz-fte-form-label" }, label),
|
43
|
+
react_2.default.createElement("div", { className: "relative text-md text-gray-800" },
|
44
|
+
react_2.default.createElement(react_1.Listbox.Button, { className: "w-full cursor-default rounded border-2 border-gray-300 bg-white py-2 pl-3 pr-10 focus:border-blue-300 focus:outline-none" },
|
45
|
+
react_2.default.createElement("span", { className: "flex items-center" },
|
46
|
+
react_2.default.createElement("span", { className: "block truncate" },
|
47
|
+
selectedOption?.label,
|
48
|
+
"\u00A0")),
|
49
|
+
react_2.default.createElement("span", { className: "pointer-events-none absolute inset-y-0 right-0 ml-3 flex items-center pr-2" }, !open ? (react_2.default.createElement(ExpandMoreRounded_1.default, { className: "text-gray-500", "aria-hidden": "true" })) : (react_2.default.createElement(ExpandLessRounded_1.default, { className: "text-gray-500", "aria-hidden": "true" })))),
|
50
|
+
react_2.default.createElement(react_1.Listbox.Options, { className: "absolute z-10 mt-1 w-full overflow-auto rounded border-2 border-gray-300 bg-white" }, Object.entries(options).map(([key, option]) => (react_2.default.createElement(react_1.Listbox.Option, { key: key, value: key, className: ({ active }) => (0, clsx_1.default)(active ? 'bg-gray-100' : 'bg-white', 'relative cursor-default select-none flex hover:bg-gray-100 py-2 px-3') },
|
51
|
+
react_2.default.createElement("span", { className: "block truncate" }, option.label))))))))));
|
52
|
+
};
|
53
|
+
exports.Select = Select;
|
@@ -1,11 +1,39 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
+
}) : function(o, v) {
|
16
|
+
o["default"] = v;
|
17
|
+
});
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
19
|
+
if (mod && mod.__esModule) return mod;
|
20
|
+
var result = {};
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
22
|
+
__setModuleDefault(result, mod);
|
23
|
+
return result;
|
24
|
+
};
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
27
|
+
};
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
29
|
+
const react_1 = __importStar(require("react"));
|
30
|
+
const Modal_1 = __importDefault(require("./Modal"));
|
3
31
|
const FormModal = (props) => {
|
4
|
-
const ref = createRef();
|
32
|
+
const ref = (0, react_1.createRef)();
|
5
33
|
const handleSubmit = () => {
|
6
34
|
const form = ref.current?.querySelector('form');
|
7
35
|
form?.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
|
8
36
|
};
|
9
|
-
return
|
37
|
+
return react_1.default.createElement(Modal_1.default, { ref: ref, ...props, onSubmit: handleSubmit });
|
10
38
|
};
|
11
|
-
|
39
|
+
exports.default = FormModal;
|
package/lib/ui/Modal/Modal.js
CHANGED
@@ -1,9 +1,37 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
+
}) : function(o, v) {
|
16
|
+
o["default"] = v;
|
17
|
+
});
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
19
|
+
if (mod && mod.__esModule) return mod;
|
20
|
+
var result = {};
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
22
|
+
__setModuleDefault(result, mod);
|
23
|
+
return result;
|
24
|
+
};
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
27
|
+
};
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
29
|
+
const react_1 = __importStar(require("react"));
|
30
|
+
const react_dom_1 = require("react-dom");
|
31
|
+
const CloseRounded_1 = __importDefault(require("@mui/icons-material/CloseRounded"));
|
32
|
+
const base_1 = require("@mui/base");
|
5
33
|
const Modal = ({ children, title, onCancel, onSubmit, className }, ref) => {
|
6
|
-
const container = useMemo(() => {
|
34
|
+
const container = (0, react_1.useMemo)(() => {
|
7
35
|
const element = document.createElement('div');
|
8
36
|
element.classList.add('squiz-fte-scope');
|
9
37
|
return element;
|
@@ -17,12 +45,12 @@ const Modal = ({ children, title, onCancel, onSubmit, className }, ref) => {
|
|
17
45
|
}
|
18
46
|
};
|
19
47
|
// register key listeners for Enter/Escape on key up so the editor doesn't handle the event as well
|
20
|
-
useEffect(() => {
|
48
|
+
(0, react_1.useEffect)(() => {
|
21
49
|
window.addEventListener('keyup', keydown);
|
22
50
|
return () => window.removeEventListener('keyup', keydown);
|
23
51
|
}, []);
|
24
52
|
// add/remove the modal container from the DOM and focus on the first input
|
25
|
-
useEffect(() => {
|
53
|
+
(0, react_1.useEffect)(() => {
|
26
54
|
const firstInput = container.querySelector('input:not([type=hidden])');
|
27
55
|
document.body.appendChild(container);
|
28
56
|
firstInput?.focus();
|
@@ -30,19 +58,19 @@ const Modal = ({ children, title, onCancel, onSubmit, className }, ref) => {
|
|
30
58
|
document.body.removeChild(container);
|
31
59
|
};
|
32
60
|
}, [container]);
|
33
|
-
return createPortal(
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
onSubmit && (
|
46
|
-
|
61
|
+
return (0, react_dom_1.createPortal)(react_1.default.createElement(react_1.default.Fragment, null,
|
62
|
+
react_1.default.createElement(base_1.FocusTrap, { open: true },
|
63
|
+
react_1.default.createElement("div", { ref: ref, className: `squiz-fte-modal-wrapper ${className ? className : ''}`, tabIndex: -1 },
|
64
|
+
react_1.default.createElement("div", { className: "w-modal-sm my-6 mx-auto" },
|
65
|
+
react_1.default.createElement("div", { className: "squiz-fte-modal" },
|
66
|
+
react_1.default.createElement("div", { className: "squiz-fte-modal-header p-6 pb-2" },
|
67
|
+
react_1.default.createElement("h2", { className: "font-semibold text-gray-900 text-heading-2" }, title),
|
68
|
+
react_1.default.createElement("button", { type: "button", className: "ml-auto -mr-3 -mt-3 bg-transparent border-0 text-gray-600 font-semibold outline-none focus:outline-none hover:text-color-gray-800", onClick: onCancel, "aria-label": "Close" },
|
69
|
+
react_1.default.createElement(CloseRounded_1.default, null))),
|
70
|
+
react_1.default.createElement("div", { className: "squiz-fte-modal-content" }, children),
|
71
|
+
react_1.default.createElement("div", { className: "squiz-fte-modal-footer p-6 pt-3" },
|
72
|
+
react_1.default.createElement("button", { className: "squiz-fte-modal-footer__button bg-gray-200 text-gray-700 mr-2 hover:bg-gray-300", type: "button", onClick: onCancel, "aria-label": "Cancel" }, "Cancel"),
|
73
|
+
onSubmit && (react_1.default.createElement("button", { className: "squiz-fte-modal-footer__button bg-blue-300 text-white hover:bg-blue-400", type: "button", onClick: onSubmit, "aria-label": "Apply" }, "Apply"))))))),
|
74
|
+
react_1.default.createElement("div", { className: "opacity-25 fixed inset-0 z-40 bg-black" })), container);
|
47
75
|
};
|
48
|
-
|
76
|
+
exports.default = (0, react_1.forwardRef)(Modal);
|
@@ -1,7 +1,35 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
+
}) : function(o, v) {
|
16
|
+
o["default"] = v;
|
17
|
+
});
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
19
|
+
if (mod && mod.__esModule) return mod;
|
20
|
+
var result = {};
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
22
|
+
__setModuleDefault(result, mod);
|
23
|
+
return result;
|
24
|
+
};
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
27
|
+
};
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
29
|
+
const react_1 = __importStar(require("react"));
|
30
|
+
const ExpandMore_1 = __importDefault(require("@mui/icons-material/ExpandMore"));
|
3
31
|
const ToolbarDropdown = ({ children, label }) => {
|
4
|
-
const [isOpen, setOpen] = useState(false);
|
32
|
+
const [isOpen, setOpen] = (0, react_1.useState)(false);
|
5
33
|
const handleDropDown = () => {
|
6
34
|
setOpen(!isOpen);
|
7
35
|
};
|
@@ -10,11 +38,11 @@ const ToolbarDropdown = ({ children, label }) => {
|
|
10
38
|
isOpen && handleDropDown();
|
11
39
|
}
|
12
40
|
};
|
13
|
-
return (
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
41
|
+
return (react_1.default.createElement("div", { className: "toolbar-dropdown", onBlur: handleBlur },
|
42
|
+
react_1.default.createElement("button", { id: "dropdownHoverButton", className: "toolbar-dropdown__button", type: "button", onClick: handleDropDown },
|
43
|
+
react_1.default.createElement("span", { className: "toolbar-dropdown__label" }, label),
|
44
|
+
react_1.default.createElement(ExpandMore_1.default, { className: "toolbar-dropdown__icon", "aria-hidden": "true" })),
|
45
|
+
react_1.default.createElement("div", { id: "dropdown", className: `toolbar-dropdown__menu z-10 ${isOpen ? 'block' : 'hidden'} bg-white divide-y w-169` },
|
46
|
+
react_1.default.createElement("ul", { "aria-labelledby": "dropdownHoverButton", onClick: handleDropDown }, children))));
|
19
47
|
};
|
20
|
-
|
48
|
+
exports.default = ToolbarDropdown;
|
@@ -1,8 +1,13 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
const react_1 = __importDefault(require("react"));
|
7
|
+
const Check_1 = __importDefault(require("@mui/icons-material/Check"));
|
3
8
|
const DropdownButton = ({ children, handleOnClick, isDisabled, isActive, label }) => {
|
4
|
-
return (
|
5
|
-
|
6
|
-
isActive &&
|
9
|
+
return (react_1.default.createElement("button", { "aria-label": label, id: "dropdownMenuButton", title: label, type: "button", onClick: handleOnClick, disabled: isDisabled, className: `btn dropdown-button ${isActive ? 'is-active' : ''}` },
|
10
|
+
react_1.default.createElement("span", null, children || label),
|
11
|
+
isActive && react_1.default.createElement(Check_1.default, { className: "dropdown-button-icon" })));
|
7
12
|
};
|
8
|
-
|
13
|
+
exports.default = DropdownButton;
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import { ProsemirrorNode } from 'remirror';
|
2
|
+
import { FORMATTED_TEXT_MODELS as FormattedTextModels } from '@squiz/dx-json-schema-lib';
|
3
|
+
export declare const resolveNodeTag: (node: ProsemirrorNode) => string | null;
|
4
|
+
/**
|
5
|
+
* Converts Remirror node JSON structure to Squiz component JSON structure.
|
6
|
+
* @param {ProsemirrorNode} node Remirror node to convert to component.
|
7
|
+
* @export
|
8
|
+
* @returns {FormattedText} The converted Squiz component JSON.
|
9
|
+
*/
|
10
|
+
export declare const remirrorNodeToSquizNode: (node: ProsemirrorNode) => FormattedTextModels.v1.FormattedText;
|
@@ -0,0 +1,160 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.remirrorNodeToSquizNode = exports.resolveNodeTag = void 0;
|
4
|
+
const validNodeTypes_1 = require("../validNodeTypes");
|
5
|
+
const resolveNodeTag = (node) => {
|
6
|
+
if (node.type.spec?.toDOM) {
|
7
|
+
const domNode = node.type.spec.toDOM(node);
|
8
|
+
if (domNode instanceof window.Node) {
|
9
|
+
return domNode.nodeName.toLowerCase();
|
10
|
+
}
|
11
|
+
if (domNode?.dom instanceof window.Node) {
|
12
|
+
return domNode.dom.nodeName.toLowerCase();
|
13
|
+
}
|
14
|
+
if (domNode instanceof Array) {
|
15
|
+
// [ tag, attributes, ...children ]
|
16
|
+
return domNode[0].toLowerCase();
|
17
|
+
}
|
18
|
+
}
|
19
|
+
return null;
|
20
|
+
};
|
21
|
+
exports.resolveNodeTag = resolveNodeTag;
|
22
|
+
const resolveFormattingOptions = (node) => {
|
23
|
+
const formattingOptions = {};
|
24
|
+
if (node.attrs.nodeTextAlignment) {
|
25
|
+
formattingOptions.alignment = node.attrs.nodeTextAlignment;
|
26
|
+
}
|
27
|
+
return formattingOptions;
|
28
|
+
};
|
29
|
+
const resolveFontOptions = (node) => {
|
30
|
+
const fontOptions = {};
|
31
|
+
node.marks.forEach((mark) => {
|
32
|
+
switch (mark.type.name) {
|
33
|
+
case 'bold':
|
34
|
+
fontOptions.bold = true;
|
35
|
+
break;
|
36
|
+
case 'italic':
|
37
|
+
fontOptions.italics = true;
|
38
|
+
break;
|
39
|
+
case 'underline':
|
40
|
+
fontOptions.underline = true;
|
41
|
+
break;
|
42
|
+
default:
|
43
|
+
// Currently unsupported mark type
|
44
|
+
break;
|
45
|
+
}
|
46
|
+
});
|
47
|
+
return fontOptions;
|
48
|
+
};
|
49
|
+
const resolveAttributeOptions = (node, nodeType) => {
|
50
|
+
let attributeOptions = {};
|
51
|
+
if (nodeType === 'image') {
|
52
|
+
attributeOptions = { ...node.attrs };
|
53
|
+
}
|
54
|
+
else {
|
55
|
+
node.marks.forEach((mark) => {
|
56
|
+
switch (mark.type.name) {
|
57
|
+
case 'link':
|
58
|
+
attributeOptions = { ...mark.attrs };
|
59
|
+
break;
|
60
|
+
default:
|
61
|
+
// Currently unsupported mark type
|
62
|
+
break;
|
63
|
+
}
|
64
|
+
});
|
65
|
+
}
|
66
|
+
// Remove any non string elements from attributes, squiz component only accepts strings.
|
67
|
+
Object.keys(attributeOptions).forEach((key) => {
|
68
|
+
if (typeof attributeOptions[key] !== 'string' && typeof attributeOptions[key] !== 'number') {
|
69
|
+
delete attributeOptions[key];
|
70
|
+
// If it's a number we make it a string so its accepted by component service
|
71
|
+
}
|
72
|
+
else {
|
73
|
+
attributeOptions[key] = String(attributeOptions[key]);
|
74
|
+
}
|
75
|
+
});
|
76
|
+
return attributeOptions;
|
77
|
+
};
|
78
|
+
/**
|
79
|
+
* Converts Remirror node JSON structure to Squiz component JSON structure.
|
80
|
+
* @param {ProsemirrorNode} node Remirror node to convert to component.
|
81
|
+
* @export
|
82
|
+
* @returns {FormattedText} The converted Squiz component JSON.
|
83
|
+
*/
|
84
|
+
const remirrorNodeToSquizNode = (node) => {
|
85
|
+
if (!(0, validNodeTypes_1.validRemirrorNode)(node))
|
86
|
+
return [];
|
87
|
+
const nodeType = node.type.name;
|
88
|
+
let nodeTag = (0, exports.resolveNodeTag)(node);
|
89
|
+
// Filter out any children nodes that aren't currently supported.
|
90
|
+
const children = (node.content.content || []).map((child) => (0, exports.remirrorNodeToSquizNode)(child));
|
91
|
+
let transformed = {
|
92
|
+
children,
|
93
|
+
formattingOptions: resolveFormattingOptions(node),
|
94
|
+
attributes: resolveAttributeOptions(node, nodeType),
|
95
|
+
font: resolveFontOptions(node),
|
96
|
+
};
|
97
|
+
if (nodeType === 'doc') {
|
98
|
+
return transformed.children;
|
99
|
+
}
|
100
|
+
// If we don't have a node tag yet, check if there is one needed
|
101
|
+
if (!nodeTag) {
|
102
|
+
node.marks.forEach((mark) => {
|
103
|
+
switch (mark.type.name) {
|
104
|
+
case 'link':
|
105
|
+
nodeTag = 'a';
|
106
|
+
break;
|
107
|
+
default:
|
108
|
+
// Currently unsupported mark type
|
109
|
+
break;
|
110
|
+
}
|
111
|
+
});
|
112
|
+
}
|
113
|
+
if (nodeTag) {
|
114
|
+
transformed = {
|
115
|
+
...transformed,
|
116
|
+
type: 'tag',
|
117
|
+
tag: nodeTag,
|
118
|
+
};
|
119
|
+
}
|
120
|
+
if ((Object.keys(transformed.font).length > 0 || Object.keys(transformed.attributes).length > 0) &&
|
121
|
+
!transformed.type) {
|
122
|
+
// Wrap in span so we can apply formatting to it
|
123
|
+
transformed = { ...transformed, tag: 'span', type: 'tag' };
|
124
|
+
}
|
125
|
+
if (nodeType === 'text') {
|
126
|
+
if (transformed.type) {
|
127
|
+
// If we have a tag already nest the text beneath it so we can preserve formatting options, etc.
|
128
|
+
transformed = {
|
129
|
+
...transformed,
|
130
|
+
children: [
|
131
|
+
{
|
132
|
+
type: 'text',
|
133
|
+
value: node.text,
|
134
|
+
},
|
135
|
+
],
|
136
|
+
};
|
137
|
+
}
|
138
|
+
else {
|
139
|
+
// If we don't have a tag just rewrite the transformed value to be the text.
|
140
|
+
transformed = {
|
141
|
+
type: 'text',
|
142
|
+
value: node.text,
|
143
|
+
};
|
144
|
+
}
|
145
|
+
}
|
146
|
+
// Remove empty formatting options from transformed object.
|
147
|
+
if (transformed.formattingOptions && Object.keys(transformed.formattingOptions).length === 0) {
|
148
|
+
delete transformed.formattingOptions;
|
149
|
+
}
|
150
|
+
// Remove empty font options from transformed object.
|
151
|
+
if (transformed.font && Object.keys(transformed.font).length === 0) {
|
152
|
+
delete transformed.font;
|
153
|
+
}
|
154
|
+
// Remove empty attributes options from transformed object.
|
155
|
+
if (transformed.attributes && Object.keys(transformed.attributes).length === 0) {
|
156
|
+
delete transformed.attributes;
|
157
|
+
}
|
158
|
+
return transformed;
|
159
|
+
};
|
160
|
+
exports.remirrorNodeToSquizNode = remirrorNodeToSquizNode;
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import { RemirrorJSON } from '@remirror/core';
|
2
|
+
import { FORMATTED_TEXT_MODELS as FormattedTextModels } from '@squiz/dx-json-schema-lib';
|
3
|
+
/**
|
4
|
+
* Converts Squiz component JSON structure to Remirror node JSON structure.
|
5
|
+
* @param {FormattedText} nodes Squiz nodes to convert to Remirror.
|
6
|
+
* @export
|
7
|
+
* @returns {RemirrorJSON} The converted Remirror JSON.
|
8
|
+
*/
|
9
|
+
export declare const squizNodeToRemirrorNode: (nodes: FormattedTextModels.v1.FormattedText) => RemirrorJSON;
|
@@ -0,0 +1,105 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.squizNodeToRemirrorNode = void 0;
|
4
|
+
const getNodeType = (node) => {
|
5
|
+
const nodeTypeMap = {
|
6
|
+
h1: 'heading',
|
7
|
+
h2: 'heading',
|
8
|
+
h3: 'heading',
|
9
|
+
h4: 'heading',
|
10
|
+
h5: 'heading',
|
11
|
+
h6: 'heading',
|
12
|
+
img: 'image',
|
13
|
+
pre: 'preformatted',
|
14
|
+
p: 'paragraph',
|
15
|
+
text: 'paragraph',
|
16
|
+
};
|
17
|
+
const nodeType = nodeTypeMap[node.tag || node.type];
|
18
|
+
// Unsupported node type
|
19
|
+
if (!nodeType)
|
20
|
+
throw new Error(`Unsupported node type provided: ${node.tag}`);
|
21
|
+
return nodeType;
|
22
|
+
};
|
23
|
+
const getNodeAttributes = (node) => {
|
24
|
+
const { alignment } = node.formattingOptions || {};
|
25
|
+
return {
|
26
|
+
nodeIndent: null,
|
27
|
+
nodeTextAlignment: alignment ?? null,
|
28
|
+
nodeLineHeight: null,
|
29
|
+
style: '',
|
30
|
+
level: node.tag?.startsWith('h') ? parseInt(node.tag.substring(1)) : undefined,
|
31
|
+
};
|
32
|
+
};
|
33
|
+
const resolveChild = (child) => {
|
34
|
+
if (child.type === 'text') {
|
35
|
+
return { type: 'text', text: child.value };
|
36
|
+
}
|
37
|
+
let text = '';
|
38
|
+
const marks = [];
|
39
|
+
if (child.type === 'tag') {
|
40
|
+
// Handle link type
|
41
|
+
if (child.tag === 'a') {
|
42
|
+
marks.push({
|
43
|
+
type: 'link',
|
44
|
+
attrs: {
|
45
|
+
href: child.attributes?.href,
|
46
|
+
target: child.attributes?.target ?? null,
|
47
|
+
auto: false,
|
48
|
+
title: child.attributes?.title ?? null,
|
49
|
+
},
|
50
|
+
});
|
51
|
+
}
|
52
|
+
// Handle image type
|
53
|
+
if (child.tag === 'img') {
|
54
|
+
return {
|
55
|
+
type: 'image',
|
56
|
+
attrs: {
|
57
|
+
alt: child.attributes?.alt,
|
58
|
+
height: child.attributes?.height,
|
59
|
+
width: child.attributes?.width,
|
60
|
+
src: child.attributes?.src,
|
61
|
+
title: child.attributes?.title,
|
62
|
+
},
|
63
|
+
};
|
64
|
+
}
|
65
|
+
// Handle font formatting
|
66
|
+
child.font?.bold && marks.push({ type: 'bold' });
|
67
|
+
child.font?.italics && marks.push({ type: 'italic' });
|
68
|
+
child.font?.underline && marks.push({ type: 'underline' });
|
69
|
+
// For now all children types should be "text"
|
70
|
+
text = child.children[0].type === 'text' ? child.children[0].value : '';
|
71
|
+
}
|
72
|
+
return { type: 'text', marks, text };
|
73
|
+
};
|
74
|
+
const formatNode = (node) => {
|
75
|
+
let content;
|
76
|
+
if (node.type === 'tag') {
|
77
|
+
content = node.children.length ? node.children.map((child) => resolveChild(child)) : undefined;
|
78
|
+
}
|
79
|
+
if (node.type === 'text') {
|
80
|
+
content = [
|
81
|
+
{
|
82
|
+
type: 'text',
|
83
|
+
text: node.value,
|
84
|
+
},
|
85
|
+
];
|
86
|
+
}
|
87
|
+
return {
|
88
|
+
type: getNodeType(node),
|
89
|
+
attrs: getNodeAttributes(node),
|
90
|
+
content,
|
91
|
+
};
|
92
|
+
};
|
93
|
+
/**
|
94
|
+
* Converts Squiz component JSON structure to Remirror node JSON structure.
|
95
|
+
* @param {FormattedText} nodes Squiz nodes to convert to Remirror.
|
96
|
+
* @export
|
97
|
+
* @returns {RemirrorJSON} The converted Remirror JSON.
|
98
|
+
*/
|
99
|
+
const squizNodeToRemirrorNode = (nodes) => {
|
100
|
+
return {
|
101
|
+
type: 'doc',
|
102
|
+
content: nodes.filter((node) => getNodeType(node)).map(formatNode),
|
103
|
+
};
|
104
|
+
};
|
105
|
+
exports.squizNodeToRemirrorNode = squizNodeToRemirrorNode;
|
@@ -0,0 +1,21 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.validRemirrorNode = void 0;
|
4
|
+
const Extensions_1 = require("../../Extensions/Extensions");
|
5
|
+
const validRemirrorNode = (node) => {
|
6
|
+
if (!node)
|
7
|
+
return false;
|
8
|
+
const nodeType = node.type.name;
|
9
|
+
const nodeMarks = node.marks;
|
10
|
+
// This is pulling in the currently supported extensions, this works for now...
|
11
|
+
// Could also just hard code these in as we go, but this should make it easier as we add more extensions
|
12
|
+
const supportedNodes = [...(0, Extensions_1.Extensions)().map((extension) => extension.name), 'doc', 'text'];
|
13
|
+
if (!supportedNodes.includes(nodeType))
|
14
|
+
return false;
|
15
|
+
for (let i = 0; i < nodeMarks.length; i++) {
|
16
|
+
if (!supportedNodes.includes(nodeMarks[i].type.name))
|
17
|
+
return false;
|
18
|
+
}
|
19
|
+
return true;
|
20
|
+
};
|
21
|
+
exports.validRemirrorNode = validRemirrorNode;
|
@@ -1,27 +1,30 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.createToolbarPositioner = void 0;
|
4
|
+
const extensions_1 = require("remirror/extensions");
|
5
|
+
const remirror_1 = require("remirror");
|
6
|
+
const getCursorRect_1 = require("./getCursorRect");
|
4
7
|
/* istanbul ignore next */
|
5
|
-
|
8
|
+
const createToolbarPositioner = ({ types }) => {
|
6
9
|
// Inspired by "createMarkPositioner".
|
7
10
|
// See: https://github.com/remirror/remirror/blob/107cba/packages/remirror__extension-positioner/src/core-positioners.ts#L267
|
8
|
-
return Positioner.create({
|
9
|
-
hasChanged: hasStateChanged,
|
11
|
+
return extensions_1.Positioner.create({
|
12
|
+
hasChanged: extensions_1.hasStateChanged,
|
10
13
|
getActive: (props) => {
|
11
14
|
const { state, view } = props;
|
12
15
|
try {
|
13
|
-
const selection = getTextSelection(state.selection, state.doc);
|
16
|
+
const selection = (0, remirror_1.getTextSelection)(state.selection, state.doc);
|
14
17
|
const cursor = { from: view.coordsAtPos(selection.from), to: view.coordsAtPos(selection.to) };
|
15
18
|
const data = {
|
16
|
-
isSelectionInView: isPositionVisible(getCursorRect(cursor.from), view.dom) ||
|
17
|
-
isPositionVisible(getCursorRect(cursor.to), view.dom),
|
19
|
+
isSelectionInView: (0, extensions_1.isPositionVisible)((0, getCursorRect_1.getCursorRect)(cursor.from), view.dom) ||
|
20
|
+
(0, extensions_1.isPositionVisible)((0, getCursorRect_1.getCursorRect)(cursor.to), view.dom),
|
18
21
|
cursor: cursor,
|
19
22
|
visible: false,
|
20
23
|
marks: {},
|
21
24
|
};
|
22
25
|
data.visible = !selection.empty && data.isSelectionInView;
|
23
26
|
types.forEach((type) => {
|
24
|
-
const markRange = getMarkRange(selection.$from, type, selection.$to);
|
27
|
+
const markRange = (0, remirror_1.getMarkRange)(selection.$from, type, selection.$to);
|
25
28
|
if (!markRange) {
|
26
29
|
data.marks[type] = { isActive: false, isExclusivelyActive: false };
|
27
30
|
return;
|
@@ -41,10 +44,10 @@ export const createToolbarPositioner = ({ types }) => {
|
|
41
44
|
data.visible = data.visible || isExclusivelyActive;
|
42
45
|
data.marks[type] = { isExclusivelyActive, isActive };
|
43
46
|
});
|
44
|
-
return data.visible ? [data] : Positioner.EMPTY;
|
47
|
+
return data.visible ? [data] : extensions_1.Positioner.EMPTY;
|
45
48
|
}
|
46
49
|
catch {
|
47
|
-
return Positioner.EMPTY;
|
50
|
+
return extensions_1.Positioner.EMPTY;
|
48
51
|
}
|
49
52
|
},
|
50
53
|
getPosition: (props) => {
|
@@ -79,3 +82,4 @@ export const createToolbarPositioner = ({ types }) => {
|
|
79
82
|
},
|
80
83
|
});
|
81
84
|
};
|
85
|
+
exports.createToolbarPositioner = createToolbarPositioner;
|