@squiz/formatted-text-editor 1.40.1-alpha.9 → 1.41.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/demo/AppContext.tsx +14 -3
- package/demo/resources.json +135 -3
- package/lib/Editor/Editor.js +3 -2
- package/lib/EditorToolbar/Toolbar.js +2 -3
- package/lib/EditorToolbar/Tools/Image/ImageButton.js +1 -1
- package/lib/EditorToolbar/Tools/Lists/ListButtons.d.ts +2 -0
- package/lib/EditorToolbar/Tools/Lists/ListButtons.js +14 -0
- package/lib/EditorToolbar/Tools/Lists/OrderedList/OrderedListButton.d.ts +2 -0
- package/lib/EditorToolbar/Tools/Lists/OrderedList/OrderedListButton.js +22 -0
- package/lib/EditorToolbar/Tools/{UnorderedList → Lists/UnorderedList}/UnorderedListButton.js +1 -1
- package/lib/Extensions/Extensions.d.ts +2 -1
- package/lib/Extensions/Extensions.js +7 -1
- package/lib/Extensions/FetchUrlExtension/FetchUrlExtension.d.ts +14 -0
- package/lib/Extensions/FetchUrlExtension/FetchUrlExtension.js +63 -0
- package/lib/Extensions/ImageExtension/AssetImageExtension.d.ts +1 -0
- package/lib/Extensions/ImageExtension/AssetImageExtension.js +4 -4
- package/lib/Extensions/LinkExtension/AssetLinkExtension.d.ts +2 -0
- package/lib/Extensions/LinkExtension/AssetLinkExtension.js +4 -4
- package/lib/hooks/useFocus.js +24 -5
- package/lib/index.css +9 -1
- package/lib/ui/Fields/MatrixAsset/MatrixAsset.d.ts +1 -0
- package/lib/ui/Fields/MatrixAsset/MatrixAsset.js +1 -0
- package/lib/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.js +2 -1
- package/package.json +4 -4
- package/src/Editor/Editor.spec.tsx +91 -16
- package/src/Editor/Editor.tsx +3 -2
- package/src/EditorToolbar/Toolbar.tsx +2 -3
- package/src/EditorToolbar/Tools/Image/ImageButton.spec.tsx +12 -2
- package/src/EditorToolbar/Tools/Image/ImageButton.tsx +1 -1
- package/src/EditorToolbar/Tools/Link/LinkButton.spec.tsx +14 -2
- package/src/EditorToolbar/Tools/Lists/ListButtons.tsx +14 -0
- package/src/EditorToolbar/Tools/Lists/OrderedList/OrderListButton.spec.tsx +39 -0
- package/src/EditorToolbar/Tools/Lists/OrderedList/OrderedListButton.tsx +30 -0
- package/src/EditorToolbar/Tools/{UnorderedList → Lists/UnorderedList}/UnorderedList.spec.tsx +1 -1
- package/src/EditorToolbar/Tools/{UnorderedList → Lists/UnorderedList}/UnorderedListButton.tsx +1 -1
- package/src/Extensions/Extensions.ts +10 -2
- package/src/Extensions/FetchUrlExtension/FetchUrlExtension.ts +73 -0
- package/src/Extensions/ImageExtension/AssetImageExtension.spec.ts +2 -1
- package/src/Extensions/ImageExtension/AssetImageExtension.ts +5 -5
- package/src/Extensions/LinkExtension/AssetLinkExtension.spec.ts +3 -1
- package/src/Extensions/LinkExtension/AssetLinkExtension.ts +6 -5
- package/src/hooks/useFocus.ts +30 -7
- package/src/ui/Fields/MatrixAsset/MatrixAsset.spec.tsx +1 -0
- package/src/ui/Fields/MatrixAsset/MatrixAsset.tsx +2 -0
- package/src/ui/_typography.scss +10 -1
- package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.spec.ts +73 -0
- package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.ts +2 -1
- package/src/utils/getNodeNamesByGroup.spec.ts +1 -0
- package/tests/mockResourceBrowserContext.tsx +2 -2
- package/tests/renderWithContext.tsx +30 -1
- package/tests/renderWithEditor.tsx +18 -13
- package/lib/utils/resolveMatrixAssetUrl.d.ts +0 -1
- package/lib/utils/resolveMatrixAssetUrl.js +0 -10
- package/src/utils/resolveMatrixAssetUrl.spec.ts +0 -26
- package/src/utils/resolveMatrixAssetUrl.ts +0 -7
- /package/lib/EditorToolbar/Tools/{UnorderedList → Lists/UnorderedList}/UnorderedListButton.d.ts +0 -0
package/demo/AppContext.tsx
CHANGED
@@ -10,9 +10,20 @@ export const AppContext = ({ children }: AppContextProps) => (
|
|
10
10
|
<ResourceBrowserContext.Provider
|
11
11
|
value={{
|
12
12
|
onRequestSources: (): Promise<Source> => Promise.resolve(sources),
|
13
|
-
onRequestChildren: (): Promise<Resource[]> =>
|
14
|
-
|
15
|
-
|
13
|
+
onRequestChildren: (source: Source, resource: Resource | null): Promise<Resource[]> =>
|
14
|
+
Promise.resolve(resource._children || resources),
|
15
|
+
onRequestResource: (reference: ResourceReference): Promise<Resource | null> => {
|
16
|
+
const flattenResources = (resources: unknown[]) => {
|
17
|
+
return [
|
18
|
+
...resources,
|
19
|
+
...resources.flatMap((resource) => ('_children' in resource ? flattenResources(resource._children) : [])),
|
20
|
+
];
|
21
|
+
};
|
22
|
+
|
23
|
+
return Promise.resolve(
|
24
|
+
flattenResources(resources).find((resource) => resource.id === reference.resource) || null,
|
25
|
+
);
|
26
|
+
},
|
16
27
|
}}
|
17
28
|
>
|
18
29
|
<EditorContext.Provider
|
package/demo/resources.json
CHANGED
@@ -9,11 +9,26 @@
|
|
9
9
|
"code": "live",
|
10
10
|
"name": "Live"
|
11
11
|
},
|
12
|
-
"name": "Example image",
|
13
|
-
"childCount": 0
|
12
|
+
"name": "Example image one",
|
13
|
+
"childCount": 0,
|
14
|
+
"url": "https://picsum.photos/200/300"
|
14
15
|
},
|
15
16
|
{
|
16
17
|
"id": "2",
|
18
|
+
"type": {
|
19
|
+
"code": "image",
|
20
|
+
"name": "Image"
|
21
|
+
},
|
22
|
+
"status": {
|
23
|
+
"code": "live",
|
24
|
+
"name": "Live"
|
25
|
+
},
|
26
|
+
"name": "Example image two",
|
27
|
+
"childCount": 0,
|
28
|
+
"url": "https://picsum.photos/200/300"
|
29
|
+
},
|
30
|
+
{
|
31
|
+
"id": "3",
|
17
32
|
"type": {
|
18
33
|
"code": "page_standard",
|
19
34
|
"name": "Standard Page"
|
@@ -23,6 +38,123 @@
|
|
23
38
|
"name": "Live"
|
24
39
|
},
|
25
40
|
"name": "Example page",
|
26
|
-
"childCount": 0
|
41
|
+
"childCount": 0,
|
42
|
+
"url": "https://picsum.photos/200/300"
|
43
|
+
},
|
44
|
+
{
|
45
|
+
"id": "4",
|
46
|
+
"type": {
|
47
|
+
"code": "folder",
|
48
|
+
"name": "Folder"
|
49
|
+
},
|
50
|
+
"status": {
|
51
|
+
"code": "live",
|
52
|
+
"name": "Live"
|
53
|
+
},
|
54
|
+
"name": "Example folder",
|
55
|
+
"childCount": 10,
|
56
|
+
"url": "",
|
57
|
+
"_children": [
|
58
|
+
{
|
59
|
+
"id": "5",
|
60
|
+
"type": {
|
61
|
+
"code": "image",
|
62
|
+
"name": "Image"
|
63
|
+
},
|
64
|
+
"status": {
|
65
|
+
"code": "live",
|
66
|
+
"name": "Live"
|
67
|
+
},
|
68
|
+
"name": "Example image one #2",
|
69
|
+
"childCount": 0,
|
70
|
+
"url": "https://picsum.photos/200/300"
|
71
|
+
},
|
72
|
+
{
|
73
|
+
"id": "6",
|
74
|
+
"type": {
|
75
|
+
"code": "image",
|
76
|
+
"name": "Image"
|
77
|
+
},
|
78
|
+
"status": {
|
79
|
+
"code": "live",
|
80
|
+
"name": "Live"
|
81
|
+
},
|
82
|
+
"name": "Example image two #2",
|
83
|
+
"childCount": 0,
|
84
|
+
"url": "https://picsum.photos/200/300"
|
85
|
+
},
|
86
|
+
{
|
87
|
+
"id": "7",
|
88
|
+
"type": {
|
89
|
+
"code": "page_standard",
|
90
|
+
"name": "Standard Page"
|
91
|
+
},
|
92
|
+
"status": {
|
93
|
+
"code": "live",
|
94
|
+
"name": "Live"
|
95
|
+
},
|
96
|
+
"name": "Example page #2",
|
97
|
+
"childCount": 0,
|
98
|
+
"url": "https://picsum.photos/200/300"
|
99
|
+
},
|
100
|
+
{
|
101
|
+
"id": "8",
|
102
|
+
"type": {
|
103
|
+
"code": "folder",
|
104
|
+
"name": "Folder"
|
105
|
+
},
|
106
|
+
"status": {
|
107
|
+
"code": "live",
|
108
|
+
"name": "Live"
|
109
|
+
},
|
110
|
+
"name": "Example folder #2",
|
111
|
+
"childCount": 10,
|
112
|
+
"url": "",
|
113
|
+
"_children": [
|
114
|
+
{
|
115
|
+
"id": "9",
|
116
|
+
"type": {
|
117
|
+
"code": "image",
|
118
|
+
"name": "Image"
|
119
|
+
},
|
120
|
+
"status": {
|
121
|
+
"code": "live",
|
122
|
+
"name": "Live"
|
123
|
+
},
|
124
|
+
"name": "Example image one #3",
|
125
|
+
"childCount": 0,
|
126
|
+
"url": "https://picsum.photos/200/300"
|
127
|
+
},
|
128
|
+
{
|
129
|
+
"id": "10",
|
130
|
+
"type": {
|
131
|
+
"code": "image",
|
132
|
+
"name": "Image"
|
133
|
+
},
|
134
|
+
"status": {
|
135
|
+
"code": "live",
|
136
|
+
"name": "Live"
|
137
|
+
},
|
138
|
+
"name": "Example image two #3",
|
139
|
+
"childCount": 0,
|
140
|
+
"url": "https://picsum.photos/200/300"
|
141
|
+
},
|
142
|
+
{
|
143
|
+
"id": "11",
|
144
|
+
"type": {
|
145
|
+
"code": "page_standard",
|
146
|
+
"name": "Standard Page"
|
147
|
+
},
|
148
|
+
"status": {
|
149
|
+
"code": "live",
|
150
|
+
"name": "Live"
|
151
|
+
},
|
152
|
+
"name": "Example page #3",
|
153
|
+
"childCount": 0,
|
154
|
+
"url": "https://picsum.photos/200/300"
|
155
|
+
}
|
156
|
+
]
|
157
|
+
}
|
158
|
+
]
|
27
159
|
}
|
28
160
|
]
|
package/lib/Editor/Editor.js
CHANGED
@@ -33,6 +33,7 @@ const EditorToolbar_1 = require("../EditorToolbar");
|
|
33
33
|
const EditorContext_1 = require("./EditorContext");
|
34
34
|
const Extensions_1 = require("../Extensions/Extensions");
|
35
35
|
const useFocus_1 = __importDefault(require("../hooks/useFocus"));
|
36
|
+
const resource_browser_1 = require("@squiz/resource-browser");
|
36
37
|
const WrappedEditor = () => {
|
37
38
|
const preventImagePaste = (0, react_1.useCallback)((event) => {
|
38
39
|
const { clipboardData } = event;
|
@@ -48,7 +49,7 @@ const WrappedEditor = () => {
|
|
48
49
|
};
|
49
50
|
const Editor = ({ content, editable = true, onChange, children, isFocused }) => {
|
50
51
|
const { manager, state, setState } = (0, react_2.useRemirror)({
|
51
|
-
extensions: (0, Extensions_1.createExtensions)((0, react_1.useContext)(EditorContext_1.EditorContext)),
|
52
|
+
extensions: (0, Extensions_1.createExtensions)((0, react_1.useContext)(EditorContext_1.EditorContext), (0, react_1.useContext)(resource_browser_1.ResourceBrowserContext)),
|
52
53
|
content,
|
53
54
|
selection: 'start',
|
54
55
|
stringHandler: 'html',
|
@@ -65,7 +66,7 @@ const Editor = ({ content, editable = true, onChange, children, isFocused }) =>
|
|
65
66
|
}
|
66
67
|
}, []);
|
67
68
|
return (react_1.default.createElement("div", { className: "squiz-fte-scope" },
|
68
|
-
react_1.default.createElement("div", { ref: wrapperRef, onBlur: handleBlur, onFocusCapture: handleFocus, className: (0, clsx_1.default)('
|
69
|
+
react_1.default.createElement("div", { ref: wrapperRef, onBlur: handleBlur, onFocusCapture: handleFocus, className: (0, clsx_1.default)('formatted-text-editor', !editable && 'formatted-text-editor--is-disabled') },
|
69
70
|
react_1.default.createElement(react_2.Remirror, { manager: manager, state: state, editable: editable, onChange: handleChange, placeholder: "Write something", label: "Text editor" },
|
70
71
|
editable && react_1.default.createElement(EditorToolbar_1.Toolbar, { isVisible: isVisible }),
|
71
72
|
children,
|
@@ -9,7 +9,6 @@ const react_components_1 = require("@remirror/react-components");
|
|
9
9
|
const clsx_1 = __importDefault(require("clsx"));
|
10
10
|
const ItalicButton_1 = __importDefault(require("./Tools/Italic/ItalicButton"));
|
11
11
|
const UnderlineButton_1 = __importDefault(require("./Tools/Underline/UnderlineButton"));
|
12
|
-
const UnorderedListButton_1 = __importDefault(require("./Tools/UnorderedList/UnorderedListButton"));
|
13
12
|
const BoldButton_1 = __importDefault(require("./Tools/Bold/BoldButton"));
|
14
13
|
const TextAlignButtons_1 = __importDefault(require("./Tools/TextAlign/TextAlignButtons"));
|
15
14
|
const UndoButton_1 = __importDefault(require("./Tools/Undo/UndoButton"));
|
@@ -19,6 +18,7 @@ const LinkButton_1 = __importDefault(require("./Tools/Link/LinkButton"));
|
|
19
18
|
const ImageButton_1 = __importDefault(require("./Tools/Image/ImageButton"));
|
20
19
|
const RemoveLinkButton_1 = __importDefault(require("./Tools/Link/RemoveLinkButton"));
|
21
20
|
const ClearFormattingButton_1 = __importDefault(require("./Tools/ClearFormatting/ClearFormattingButton"));
|
21
|
+
const ListButtons_1 = __importDefault(require("./Tools/Lists/ListButtons"));
|
22
22
|
const hooks_1 = require("../hooks");
|
23
23
|
const Toolbar = ({ isVisible }) => {
|
24
24
|
const extensionNames = (0, hooks_1.useExtensionNames)();
|
@@ -32,9 +32,8 @@ const Toolbar = ({ isVisible }) => {
|
|
32
32
|
extensionNames.italic && react_1.default.createElement(ItalicButton_1.default, null),
|
33
33
|
extensionNames.underline && react_1.default.createElement(UnderlineButton_1.default, null),
|
34
34
|
extensionNames.nodeFormatting && react_1.default.createElement(TextAlignButtons_1.default, null),
|
35
|
-
extensionNames.
|
35
|
+
extensionNames.listItem && react_1.default.createElement(ListButtons_1.default, null),
|
36
36
|
extensionNames.link && (react_1.default.createElement(react_1.default.Fragment, null,
|
37
|
-
react_1.default.createElement(react_components_1.VerticalDivider, null),
|
38
37
|
react_1.default.createElement(LinkButton_1.default, null),
|
39
38
|
react_1.default.createElement(RemoveLinkButton_1.default, null))),
|
40
39
|
extensionNames.image && react_1.default.createElement(ImageButton_1.default, null),
|
@@ -0,0 +1,14 @@
|
|
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 OrderedListButton_1 = __importDefault(require("./OrderedList/OrderedListButton"));
|
8
|
+
const UnorderedListButton_1 = __importDefault(require("./UnorderedList/UnorderedListButton"));
|
9
|
+
const react_components_1 = require("@remirror/react-components");
|
10
|
+
const ListButtons = () => (react_1.default.createElement(react_1.default.Fragment, null,
|
11
|
+
react_1.default.createElement(UnorderedListButton_1.default, null),
|
12
|
+
react_1.default.createElement(OrderedListButton_1.default, null),
|
13
|
+
react_1.default.createElement(react_components_1.VerticalDivider, null)));
|
14
|
+
exports.default = ListButtons;
|
@@ -0,0 +1,22 @@
|
|
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 react_2 = require("@remirror/react");
|
8
|
+
const Button_1 = __importDefault(require("../../../../ui/Button/Button"));
|
9
|
+
const FormatListNumbered_1 = __importDefault(require("@mui/icons-material/FormatListNumbered"));
|
10
|
+
const OrderedListButton = () => {
|
11
|
+
const { toggleOrderedList } = (0, react_2.useCommands)();
|
12
|
+
const chain = (0, react_2.useChainedCommands)();
|
13
|
+
const active = (0, react_2.useActive)();
|
14
|
+
const enabled = toggleOrderedList.enabled();
|
15
|
+
const handleSelect = () => {
|
16
|
+
if (toggleOrderedList.enabled()) {
|
17
|
+
chain.toggleOrderedList().focus().run();
|
18
|
+
}
|
19
|
+
};
|
20
|
+
return (react_1.default.createElement(Button_1.default, { handleOnClick: handleSelect, isDisabled: !enabled, isActive: active.orderedList(), icon: react_1.default.createElement(FormatListNumbered_1.default, null), label: "Ordered list" }));
|
21
|
+
};
|
22
|
+
exports.default = OrderedListButton;
|
package/lib/EditorToolbar/Tools/{UnorderedList → Lists/UnorderedList}/UnorderedListButton.js
RENAMED
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
6
|
const react_1 = __importDefault(require("react"));
|
7
7
|
const react_2 = require("@remirror/react");
|
8
|
-
const Button_1 = __importDefault(require("
|
8
|
+
const Button_1 = __importDefault(require("../../../../ui/Button/Button"));
|
9
9
|
const FormatListBulletedRounded_1 = __importDefault(require("@mui/icons-material/FormatListBulletedRounded"));
|
10
10
|
const UnorderedListButton = () => {
|
11
11
|
const { toggleBulletList } = (0, react_2.useCommands)();
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { Extension } from '@remirror/core';
|
2
2
|
import { EditorContextOptions } from '../Editor/EditorContext';
|
3
|
+
import { ResourceBrowserContextProps } from '@squiz/resource-browser';
|
3
4
|
export declare enum NodeName {
|
4
5
|
Image = "image",
|
5
6
|
CodeBlock = "codeBlock",
|
@@ -11,4 +12,4 @@ export declare enum MarkName {
|
|
11
12
|
Link = "link",
|
12
13
|
AssetLink = "assetLink"
|
13
14
|
}
|
14
|
-
export declare const createExtensions: (context: EditorContextOptions) => () => Extension[];
|
15
|
+
export declare const createExtensions: (context: EditorContextOptions, browserContext: ResourceBrowserContextProps) => () => Extension[];
|
@@ -11,6 +11,7 @@ const AssetImageExtension_1 = require("./ImageExtension/AssetImageExtension");
|
|
11
11
|
const CodeBlockExtension_1 = require("./CodeBlockExtension/CodeBlockExtension");
|
12
12
|
const ClearFormattingExtension_1 = require("./ClearFormattingExtension/ClearFormattingExtension");
|
13
13
|
const UnsupportedNodeExtension_1 = require("./UnsuportedExtension/UnsupportedNodeExtension");
|
14
|
+
const FetchUrlExtension_1 = require("./FetchUrlExtension/FetchUrlExtension");
|
14
15
|
var NodeName;
|
15
16
|
(function (NodeName) {
|
16
17
|
NodeName["Image"] = "image";
|
@@ -24,7 +25,7 @@ var MarkName;
|
|
24
25
|
MarkName["Link"] = "link";
|
25
26
|
MarkName["AssetLink"] = "assetLink";
|
26
27
|
})(MarkName = exports.MarkName || (exports.MarkName = {}));
|
27
|
-
const createExtensions = (context) => {
|
28
|
+
const createExtensions = (context, browserContext) => {
|
28
29
|
return () => {
|
29
30
|
return [
|
30
31
|
new CommandsExtension_1.CommandsExtension(),
|
@@ -50,6 +51,11 @@ const createExtensions = (context) => {
|
|
50
51
|
new ClearFormattingExtension_1.ClearFormattingExtension(),
|
51
52
|
new extensions_1.BulletListExtension(),
|
52
53
|
new extensions_1.ListItemExtension(),
|
54
|
+
new extensions_1.OrderedListExtension(),
|
55
|
+
new extensions_1.PlaceholderExtension(),
|
56
|
+
new FetchUrlExtension_1.FetchUrlExtension({
|
57
|
+
fetchUrl: browserContext.onRequestResource,
|
58
|
+
}),
|
53
59
|
];
|
54
60
|
};
|
55
61
|
};
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import { PlainExtension } from '@remirror/core';
|
2
|
+
import { Dispose, EditorView } from '@remirror/core-types';
|
3
|
+
export type FetchUrlOptions = {
|
4
|
+
fetchUrl?: (params: {
|
5
|
+
resource: string;
|
6
|
+
source: string;
|
7
|
+
}) => Promise<any>;
|
8
|
+
};
|
9
|
+
export declare class FetchUrlExtension extends PlainExtension<FetchUrlOptions> {
|
10
|
+
get name(): string;
|
11
|
+
onView(view: EditorView): Dispose | void;
|
12
|
+
private findAssetLinkMark;
|
13
|
+
private fetchAndReplace;
|
14
|
+
}
|
@@ -0,0 +1,63 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
5
|
+
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;
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
7
|
+
};
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
9
|
+
exports.FetchUrlExtension = void 0;
|
10
|
+
const core_1 = require("@remirror/core");
|
11
|
+
const Extensions_1 = require("../Extensions");
|
12
|
+
let FetchUrlExtension = class FetchUrlExtension extends core_1.PlainExtension {
|
13
|
+
get name() {
|
14
|
+
return 'fetchUrl';
|
15
|
+
}
|
16
|
+
// Implement the `onView` lifecycle method to scan for `[fetch]` and replace attributes
|
17
|
+
onView(view) {
|
18
|
+
const { state } = view;
|
19
|
+
const { tr } = state;
|
20
|
+
const promises = [];
|
21
|
+
state.doc.descendants((node, pos) => {
|
22
|
+
if (node.type.name === Extensions_1.NodeName.AssetImage && node.attrs.src === '') {
|
23
|
+
promises.push(this.fetchAndReplace(node.attrs.matrixAssetId, node.attrs.matrixIdentifier, (url) => {
|
24
|
+
const newNode = state.schema.nodes[Extensions_1.NodeName.AssetImage].create({ ...node.attrs, src: url });
|
25
|
+
tr.replaceWith(pos, pos + node.nodeSize, newNode);
|
26
|
+
}));
|
27
|
+
}
|
28
|
+
const assetLinkMark = this.findAssetLinkMark(node.marks);
|
29
|
+
if (node.type.name === 'text' && assetLinkMark) {
|
30
|
+
promises.push(this.fetchAndReplace(assetLinkMark.attrs.matrixAssetId, assetLinkMark.attrs.matrixIdentifier, (url) => {
|
31
|
+
const updatedMark = assetLinkMark.type.create({ ...assetLinkMark.attrs, href: url });
|
32
|
+
tr.addMark(pos, pos + node.nodeSize, updatedMark);
|
33
|
+
}));
|
34
|
+
}
|
35
|
+
});
|
36
|
+
if (promises.length) {
|
37
|
+
Promise.all(promises).then(() => {
|
38
|
+
view.dispatch(tr);
|
39
|
+
});
|
40
|
+
}
|
41
|
+
}
|
42
|
+
findAssetLinkMark(marks) {
|
43
|
+
return marks.find((mark) => mark.type.name === Extensions_1.MarkName.AssetLink && mark.attrs.href === '');
|
44
|
+
}
|
45
|
+
fetchAndReplace(resource, source, onFetched) {
|
46
|
+
return this.options
|
47
|
+
.fetchUrl({ resource, source })
|
48
|
+
.then((asset) => {
|
49
|
+
onFetched(asset.url);
|
50
|
+
})
|
51
|
+
.catch((error) => {
|
52
|
+
console.error('Error fetching URL:', error);
|
53
|
+
});
|
54
|
+
}
|
55
|
+
};
|
56
|
+
FetchUrlExtension = __decorate([
|
57
|
+
(0, core_1.extension)({
|
58
|
+
defaultOptions: {
|
59
|
+
fetchUrl: () => Promise.resolve(),
|
60
|
+
},
|
61
|
+
})
|
62
|
+
], FetchUrlExtension);
|
63
|
+
exports.FetchUrlExtension = FetchUrlExtension;
|
@@ -9,7 +9,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.AssetImageExtension = void 0;
|
10
10
|
const core_1 = require("@remirror/core");
|
11
11
|
const remirror_1 = require("remirror");
|
12
|
-
const resolveMatrixAssetUrl_1 = require("../../utils/resolveMatrixAssetUrl");
|
13
12
|
const Extensions_1 = require("../Extensions");
|
14
13
|
let AssetImageExtension = class AssetImageExtension extends core_1.NodeExtension {
|
15
14
|
get name() {
|
@@ -29,6 +28,7 @@ let AssetImageExtension = class AssetImageExtension extends core_1.NodeExtension
|
|
29
28
|
matrixAssetId: {},
|
30
29
|
matrixIdentifier: {},
|
31
30
|
matrixDomain: { default: this.options.matrixDomain },
|
31
|
+
src: { default: '' },
|
32
32
|
},
|
33
33
|
parseDOM: [
|
34
34
|
{
|
@@ -53,13 +53,13 @@ let AssetImageExtension = class AssetImageExtension extends core_1.NodeExtension
|
|
53
53
|
},
|
54
54
|
],
|
55
55
|
toDOM: (node) => {
|
56
|
-
const { matrixAssetId, matrixIdentifier, matrixDomain, ...rest } = (0, core_1.omitExtraAttributes)(node.attrs, extra);
|
56
|
+
const { matrixAssetId, matrixIdentifier, matrixDomain, src, ...rest } = (0, core_1.omitExtraAttributes)(node.attrs, extra);
|
57
57
|
return [
|
58
58
|
'img',
|
59
59
|
{
|
60
60
|
...extra.dom(node),
|
61
61
|
...rest,
|
62
|
-
src
|
62
|
+
src,
|
63
63
|
'data-matrix-asset-id': matrixAssetId,
|
64
64
|
'data-matrix-identifier': matrixIdentifier,
|
65
65
|
'data-matrix-domain': matrixDomain,
|
@@ -71,7 +71,7 @@ let AssetImageExtension = class AssetImageExtension extends core_1.NodeExtension
|
|
71
71
|
insertAssetImage(attrs) {
|
72
72
|
return ({ tr, dispatch }) => {
|
73
73
|
const { from, to } = (0, remirror_1.getTextSelection)(tr.selection, tr.doc);
|
74
|
-
const node = this.type.create(attrs);
|
74
|
+
const node = this.type.create({ ...attrs, src: attrs.url });
|
75
75
|
dispatch?.(tr.replaceRangeWith(from, to, node));
|
76
76
|
return true;
|
77
77
|
};
|
@@ -12,7 +12,6 @@ const core_1 = require("@remirror/core");
|
|
12
12
|
const common_1 = require("./common");
|
13
13
|
const CommandsExtension_1 = require("../CommandsExtension/CommandsExtension");
|
14
14
|
const Extensions_1 = require("../Extensions");
|
15
|
-
const resolveMatrixAssetUrl_1 = require("../../utils/resolveMatrixAssetUrl");
|
16
15
|
let AssetLinkExtension = class AssetLinkExtension extends core_1.MarkExtension {
|
17
16
|
get name() {
|
18
17
|
return Extensions_1.MarkName.AssetLink;
|
@@ -26,6 +25,7 @@ let AssetLinkExtension = class AssetLinkExtension extends core_1.MarkExtension {
|
|
26
25
|
...extra.defaults(),
|
27
26
|
matrixAssetId: {},
|
28
27
|
matrixIdentifier: {},
|
28
|
+
href: { default: '' },
|
29
29
|
matrixDomain: { default: this.options.matrixDomain },
|
30
30
|
target: { default: this.options.defaultTarget },
|
31
31
|
},
|
@@ -53,13 +53,13 @@ let AssetLinkExtension = class AssetLinkExtension extends core_1.MarkExtension {
|
|
53
53
|
},
|
54
54
|
],
|
55
55
|
toDOM: (node) => {
|
56
|
-
const { matrixAssetId, matrixIdentifier, matrixDomain, target, ...rest } = (0, core_1.omitExtraAttributes)(node.attrs, extra);
|
56
|
+
const { matrixAssetId, matrixIdentifier, matrixDomain, target, href, ...rest } = (0, core_1.omitExtraAttributes)(node.attrs, extra);
|
57
57
|
const rel = 'noopener noreferrer nofollow';
|
58
58
|
const attrs = {
|
59
59
|
...extra.dom(node),
|
60
60
|
...rest,
|
61
61
|
rel,
|
62
|
-
href
|
62
|
+
href,
|
63
63
|
target: (0, common_1.validateTarget)(target, this.options.supportedTargets, this.options.defaultTarget),
|
64
64
|
'data-matrix-asset-id': matrixAssetId,
|
65
65
|
'data-matrix-identifier': matrixIdentifier,
|
@@ -71,7 +71,7 @@ let AssetLinkExtension = class AssetLinkExtension extends core_1.MarkExtension {
|
|
71
71
|
}
|
72
72
|
updateAssetLink({ text, attrs, range }) {
|
73
73
|
return this.store.getExtension(CommandsExtension_1.CommandsExtension).updateMark({
|
74
|
-
attrs,
|
74
|
+
attrs: { ...attrs, href: attrs.url },
|
75
75
|
text,
|
76
76
|
range,
|
77
77
|
mark: this.type,
|
package/lib/hooks/useFocus.js
CHANGED
@@ -6,13 +6,32 @@ const useFocus = (initialState) => {
|
|
6
6
|
const [isVisible, setIsVisible] = (0, react_1.useState)(initialState);
|
7
7
|
const handleFocus = (0, react_1.useCallback)(() => {
|
8
8
|
setIsVisible(true);
|
9
|
-
}, []);
|
10
|
-
const handleBlur = (event) => {
|
11
|
-
|
12
|
-
|
9
|
+
}, [wrapperRef]);
|
10
|
+
const handleBlur = (0, react_1.useCallback)((event) => {
|
11
|
+
// React event bubbling is interesting, it bubbles up the React tree rather than the DOM tree.
|
12
|
+
// The tree deviates when rendering portals (eg. for modals).
|
13
|
+
//
|
14
|
+
// Only hide the toolbar if:
|
15
|
+
// 1. We are blurring a node in the editor **DOM** tree.
|
16
|
+
// 2. We are focusing on something that is not in the editor DOM tree
|
17
|
+
// (elements in the portal won't be in the tree but don't influence the focus state per #1).
|
18
|
+
//
|
19
|
+
// This avoids the scenario where an element in a portal is blurred and another one in the portal focused.
|
20
|
+
// Without this logic the blur and focus handlers are called (in that order). The impact of these handlers being
|
21
|
+
// called is that the "isFocused" state changes inconsistently. This state changing then causes subtle issues.
|
22
|
+
// eg. unable to drill down in resource browser, toolbar appearing/disappearing.
|
23
|
+
//
|
24
|
+
// Ideally we would instead solely seeing if the "relatedTarget" is in the React tree. This isn't easily
|
25
|
+
// identifiable however without reaching into React internals.
|
26
|
+
//
|
27
|
+
// An assumption here is that anything in a portal will only blur to another element that is also in the portal
|
28
|
+
// (and therefore still in our React tree resulting in the element still effectively being focused).
|
29
|
+
const isBlurringEditor = wrapperRef.current?.contains(event.target);
|
30
|
+
const isFocusedInEditor = wrapperRef.current?.contains(event.relatedTarget);
|
31
|
+
if (isBlurringEditor && !isFocusedInEditor) {
|
13
32
|
setIsVisible(false);
|
14
33
|
}
|
15
|
-
};
|
34
|
+
}, [wrapperRef]);
|
16
35
|
return { handleFocus, handleBlur, isVisible, wrapperRef };
|
17
36
|
};
|
18
37
|
exports.default = useFocus;
|
package/lib/index.css
CHANGED
@@ -643,6 +643,10 @@
|
|
643
643
|
color: rgb(7 116 210 / var(--tw-text-opacity));
|
644
644
|
text-decoration: underline;
|
645
645
|
}
|
646
|
+
.squiz-fte-scope .remirror-editor p {
|
647
|
+
-webkit-margin-after: 0.8rem;
|
648
|
+
margin-block-end: 0.8rem;
|
649
|
+
}
|
646
650
|
.squiz-fte-scope .remirror-editor h1 {
|
647
651
|
font-size: 1.625rem;
|
648
652
|
font-weight: 600;
|
@@ -709,11 +713,15 @@
|
|
709
713
|
padding-top: 0.75rem;
|
710
714
|
padding-bottom: 0.75rem;
|
711
715
|
}
|
712
|
-
.squiz-fte-scope .remirror-editor ul
|
716
|
+
.squiz-fte-scope .remirror-editor ul,
|
717
|
+
.squiz-fte-scope .remirror-editor ol {
|
713
718
|
list-style-type: disc;
|
714
719
|
padding: 0 0 0 2.5rem;
|
715
720
|
margin: 1rem 0;
|
716
721
|
}
|
722
|
+
.squiz-fte-scope .remirror-editor ol {
|
723
|
+
list-style-type: decimal;
|
724
|
+
}
|
717
725
|
.squiz-fte-scope .squiz-fte-form-group {
|
718
726
|
display: flex;
|
719
727
|
flex-direction: column;
|
@@ -2,6 +2,7 @@ import { InputContainerProps } from '../InputContainer/InputContainer';
|
|
2
2
|
type MatrixAssetValue = {
|
3
3
|
matrixIdentifier?: string;
|
4
4
|
matrixAssetId?: string;
|
5
|
+
url?: string;
|
5
6
|
};
|
6
7
|
export type MatrixAssetProps<T extends MatrixAssetValue> = Omit<InputContainerProps, 'children'> & {
|
7
8
|
modalTitle: string;
|
@@ -19,8 +19,9 @@ const getNodeType = (node) => {
|
|
19
19
|
img: 'image',
|
20
20
|
pre: 'preformatted',
|
21
21
|
p: 'paragraph',
|
22
|
-
|
22
|
+
ol: 'orderedList',
|
23
23
|
li: 'listItem',
|
24
|
+
ul: 'bulletList',
|
24
25
|
a: Extensions_1.NodeName.Text,
|
25
26
|
span: Extensions_1.NodeName.Text,
|
26
27
|
code: Extensions_1.NodeName.CodeBlock,
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@squiz/formatted-text-editor",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.41.1-alpha.0",
|
4
4
|
"main": "lib/index.js",
|
5
5
|
"types": "lib/index.d.ts",
|
6
6
|
"scripts": {
|
@@ -20,8 +20,8 @@
|
|
20
20
|
"@headlessui/react": "1.7.11",
|
21
21
|
"@mui/icons-material": "5.11.16",
|
22
22
|
"@remirror/react": "2.0.25",
|
23
|
-
"@squiz/dx-json-schema-lib": "1.
|
24
|
-
"@squiz/resource-browser": "1.
|
23
|
+
"@squiz/dx-json-schema-lib": "1.41.1-alpha.0",
|
24
|
+
"@squiz/resource-browser": "1.41.1-alpha.0",
|
25
25
|
"clsx": "1.2.1",
|
26
26
|
"react-hook-form": "7.43.2",
|
27
27
|
"react-image-size": "2.0.0",
|
@@ -75,5 +75,5 @@
|
|
75
75
|
"volta": {
|
76
76
|
"node": "18.15.0"
|
77
77
|
},
|
78
|
-
"gitHead": "
|
78
|
+
"gitHead": "85be9c5f7ecf79f0037fb6124a122aab38ffaa59"
|
79
79
|
}
|