@squiz/formatted-text-editor 1.16.0 → 1.21.1-alpha.2
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/jest.config.ts +8 -9
- package/lib/Editor/Editor.js +18 -13
- package/lib/EditorToolbar/FloatingToolbar.js +50 -20
- package/lib/EditorToolbar/Toolbar.js +31 -24
- package/lib/EditorToolbar/Tools/Bold/BoldButton.js +14 -9
- 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.js +17 -13
- package/lib/Extensions/LinkExtension/LinkExtension.js +17 -11
- 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 +3 -3
- package/lib/index.js +8 -2
- package/lib/ui/Inputs/Select/Select.js +46 -16
- package/lib/ui/Inputs/Text/TextInput.js +31 -5
- package/lib/ui/Modal/FormModal.js +33 -5
- package/lib/ui/Modal/Modal.js +50 -22
- package/lib/ui/ToolbarButton/ToolbarButton.js +8 -3
- package/lib/ui/ToolbarDropdown/ToolbarDropdown.js +38 -10
- package/lib/ui/ToolbarDropdownButton/ToolbarDropdownButton.js +11 -6
- package/lib/utils/createToolbarPositioner.js +16 -12
- package/lib/utils/getCursorRect.js +5 -1
- package/package.json +3 -2
- package/src/EditorToolbar/FloatingToolbar.tsx +1 -1
- package/src/EditorToolbar/_toolbar.scss +7 -7
- package/src/Extensions/LinkExtension/LinkExtension.ts +8 -5
- 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/tsconfig.json +1 -1
@@ -1,23 +1,53 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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);
|
8
37
|
const handleChange = (value) => {
|
9
38
|
setSelectedOptions(options[value]);
|
10
39
|
onChange?.(value);
|
11
40
|
};
|
12
|
-
return (
|
13
|
-
label &&
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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" },
|
18
47
|
selectedOption?.label,
|
19
48
|
"\u00A0")),
|
20
|
-
|
21
|
-
|
22
|
-
|
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))))))))));
|
23
52
|
};
|
53
|
+
exports.Select = Select;
|
@@ -1,7 +1,33 @@
|
|
1
|
-
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
26
|
+
exports.TextInput = void 0;
|
27
|
+
const react_1 = __importStar(require("react"));
|
2
28
|
const TextInputInternal = ({ name, label, ...rest }, ref) => {
|
3
|
-
return (
|
4
|
-
label && (
|
5
|
-
|
29
|
+
return (react_1.default.createElement(react_1.default.Fragment, null,
|
30
|
+
label && (react_1.default.createElement("label", { htmlFor: name, className: "squiz-fte-form-label" }, label)),
|
31
|
+
react_1.default.createElement("input", { ref: ref, id: name, name: name, type: "text", className: "squiz-fte-form-control", ...rest })));
|
6
32
|
};
|
7
|
-
|
33
|
+
exports.TextInput = (0, react_1.forwardRef)(TextInputInternal);
|
@@ -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,5 +1,10 @@
|
|
1
|
-
|
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"));
|
2
7
|
const ToolbarButton = ({ handleOnClick, isDisabled, isActive, icon, label }) => {
|
3
|
-
return (
|
8
|
+
return (react_1.default.createElement("button", { "aria-label": label, title: label, type: "button", onClick: handleOnClick, disabled: isDisabled, className: `squiz-fte-btn toolbar-button ${isActive ? 'is-active' : ''}` }, icon));
|
4
9
|
};
|
5
|
-
|
10
|
+
exports.default = ToolbarButton;
|
@@ -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;
|
@@ -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;
|
@@ -1,3 +1,7 @@
|
|
1
|
-
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.getCursorRect = void 0;
|
4
|
+
const getCursorRect = (coords) => {
|
2
5
|
return new DOMRect(coords.left, coords.top, 1, coords.top - coords.bottom);
|
3
6
|
};
|
7
|
+
exports.getCursorRect = getCursorRect;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@squiz/formatted-text-editor",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.21.1-alpha.2",
|
4
4
|
"main": "lib/index.js",
|
5
5
|
"types": "lib/index.d.ts",
|
6
6
|
"scripts": {
|
@@ -12,6 +12,7 @@
|
|
12
12
|
"dev": "vite",
|
13
13
|
"preview": "vite preview",
|
14
14
|
"test": "jest",
|
15
|
+
"test:coverage": "jest --coverage",
|
15
16
|
"test:e2e": "vite build && vite preview --port 8080 & cypress open",
|
16
17
|
"test:watch": "jest --watch"
|
17
18
|
},
|
@@ -66,5 +67,5 @@
|
|
66
67
|
"volta": {
|
67
68
|
"node": "16.19.0"
|
68
69
|
},
|
69
|
-
"gitHead": "
|
70
|
+
"gitHead": "094356f01a017174820505681d5dfc4a2ee9428b"
|
70
71
|
}
|
@@ -27,7 +27,7 @@ export const FloatingToolbar = () => {
|
|
27
27
|
} else if (!data.marks?.link.isActive) {
|
28
28
|
// if none of the selected text is a link show the option to create a link.
|
29
29
|
buttons.push(
|
30
|
-
<VerticalDivider key="link-divider" className="
|
30
|
+
<VerticalDivider key="link-divider" className="editor-divider" />,
|
31
31
|
<LinkButton key="add-link" inPopover={true} />,
|
32
32
|
);
|
33
33
|
}
|
@@ -1,16 +1,16 @@
|
|
1
|
-
.
|
1
|
+
.editor-toolbar {
|
2
2
|
@apply bg-white border-gray-200 border-b-2 border-solid p-1;
|
3
3
|
|
4
4
|
display: flex;
|
5
5
|
justify-items: center;
|
6
6
|
|
7
|
-
> *:not(:first-child) {
|
7
|
+
> *:not(:first-child, .editor-divider) {
|
8
8
|
margin: 0 0 0 2px;
|
9
9
|
}
|
10
|
+
}
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
}
|
12
|
+
.editor-divider {
|
13
|
+
@apply -my-1 mx-1 border;
|
14
|
+
margin-right: 2px;
|
15
|
+
height: auto;
|
16
16
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { ApplySchemaAttributes, getMarkRanges, isElementDomNode, MarkExtensionSpec, MarkSpecOverride } from 'remirror';
|
2
|
-
import { getTextSelection, getMarkRange, KeyBindingProps
|
2
|
+
import { getTextSelection, getMarkRange, KeyBindingProps } from '@remirror/core';
|
3
3
|
import { CommandFunction } from '@remirror/pm';
|
4
4
|
import { LinkAttributes as RemirrorLinkAttributes, LinkExtension as RemirrorLinkExtension } from 'remirror/extensions';
|
5
5
|
|
@@ -95,19 +95,22 @@ export class LinkExtension extends RemirrorLinkExtension {
|
|
95
95
|
|
96
96
|
if (text !== selectedText) {
|
97
97
|
// update the text in the editor if it was updated, update the range to cover the length of the new text.
|
98
|
-
|
98
|
+
tr.insertText(text);
|
99
99
|
range.to = range.from + text.length;
|
100
100
|
}
|
101
101
|
|
102
102
|
// apply the link, or remove it if no URL was provided.
|
103
103
|
if (attrs.href.length > 0) {
|
104
|
-
|
104
|
+
tr.addMark(range.from, range.to, this.type.create(attrs));
|
105
105
|
} else {
|
106
|
-
removeMark(
|
106
|
+
tr.removeMark(range.from, range.to, this.type);
|
107
107
|
}
|
108
108
|
|
109
109
|
// move the cursor to the end of the link and re-focus the editor.
|
110
|
-
|
110
|
+
tr.setSelection(getTextSelection({ from: range.to, to: range.to }, tr.doc));
|
111
|
+
|
112
|
+
// apply the transaction.
|
113
|
+
dispatch?.(tr);
|
111
114
|
view?.focus();
|
112
115
|
|
113
116
|
return true;
|
package/src/ui/Modal/Modal.tsx
CHANGED
@@ -56,6 +56,7 @@ const Modal = (
|
|
56
56
|
<div className="squiz-fte-modal-header p-6 pb-2">
|
57
57
|
<h2 className="font-semibold text-gray-900 text-heading-2">{title}</h2>
|
58
58
|
<button
|
59
|
+
type="button"
|
59
60
|
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"
|
60
61
|
onClick={onCancel}
|
61
62
|
aria-label="Close"
|
@@ -2,13 +2,14 @@ import '@testing-library/jest-dom';
|
|
2
2
|
import { fireEvent, render, screen } from '@testing-library/react';
|
3
3
|
import React from 'react';
|
4
4
|
import ToolbarDropdown from './ToolbarDropdown';
|
5
|
+
import ToolbarDropdownButton from '../ToolbarDropdownButton/ToolbarDropdownButton';
|
5
6
|
|
6
7
|
describe('Toolbar dropdown', () => {
|
7
8
|
const ToolbarDropdownComponent = () => {
|
8
9
|
return (
|
9
10
|
<ToolbarDropdown label="Test dropdown">
|
10
|
-
<
|
11
|
-
<
|
11
|
+
<ToolbarDropdownButton label="Test button" isDisabled={false} isActive={false} handleOnClick={jest.fn()} />
|
12
|
+
<ToolbarDropdownButton label="Test button 2" isDisabled={false} isActive={false} handleOnClick={jest.fn()} />
|
12
13
|
</ToolbarDropdown>
|
13
14
|
);
|
14
15
|
};
|
@@ -17,6 +18,7 @@ describe('Toolbar dropdown', () => {
|
|
17
18
|
render(<ToolbarDropdownComponent />);
|
18
19
|
// Check that the supplied label renders
|
19
20
|
const dropdownButton = screen.getByRole('button', { name: 'Test dropdown' });
|
21
|
+
expect(dropdownButton).toHaveAttribute('type', 'button');
|
20
22
|
expect(dropdownButton).toBeInTheDocument();
|
21
23
|
});
|
22
24
|
|
@@ -21,7 +21,7 @@ const ToolbarDropdown = ({ children, label }: ToolbarDropdownProps) => {
|
|
21
21
|
|
22
22
|
return (
|
23
23
|
<div className="toolbar-dropdown" onBlur={handleBlur}>
|
24
|
-
<button id="dropdownHoverButton" className="toolbar-dropdown__button" onClick={handleDropDown}>
|
24
|
+
<button id="dropdownHoverButton" className="toolbar-dropdown__button" type="button" onClick={handleDropDown}>
|
25
25
|
<span className="toolbar-dropdown__label">{label}</span>
|
26
26
|
<ExpandMoreIcon className="toolbar-dropdown__icon" aria-hidden="true" />
|
27
27
|
</button>
|
package/tsconfig.json
CHANGED