@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.
Files changed (56) hide show
  1. package/demo/AppContext.tsx +14 -3
  2. package/demo/resources.json +135 -3
  3. package/lib/Editor/Editor.js +3 -2
  4. package/lib/EditorToolbar/Toolbar.js +2 -3
  5. package/lib/EditorToolbar/Tools/Image/ImageButton.js +1 -1
  6. package/lib/EditorToolbar/Tools/Lists/ListButtons.d.ts +2 -0
  7. package/lib/EditorToolbar/Tools/Lists/ListButtons.js +14 -0
  8. package/lib/EditorToolbar/Tools/Lists/OrderedList/OrderedListButton.d.ts +2 -0
  9. package/lib/EditorToolbar/Tools/Lists/OrderedList/OrderedListButton.js +22 -0
  10. package/lib/EditorToolbar/Tools/{UnorderedList → Lists/UnorderedList}/UnorderedListButton.js +1 -1
  11. package/lib/Extensions/Extensions.d.ts +2 -1
  12. package/lib/Extensions/Extensions.js +7 -1
  13. package/lib/Extensions/FetchUrlExtension/FetchUrlExtension.d.ts +14 -0
  14. package/lib/Extensions/FetchUrlExtension/FetchUrlExtension.js +63 -0
  15. package/lib/Extensions/ImageExtension/AssetImageExtension.d.ts +1 -0
  16. package/lib/Extensions/ImageExtension/AssetImageExtension.js +4 -4
  17. package/lib/Extensions/LinkExtension/AssetLinkExtension.d.ts +2 -0
  18. package/lib/Extensions/LinkExtension/AssetLinkExtension.js +4 -4
  19. package/lib/hooks/useFocus.js +24 -5
  20. package/lib/index.css +9 -1
  21. package/lib/ui/Fields/MatrixAsset/MatrixAsset.d.ts +1 -0
  22. package/lib/ui/Fields/MatrixAsset/MatrixAsset.js +1 -0
  23. package/lib/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.js +2 -1
  24. package/package.json +4 -4
  25. package/src/Editor/Editor.spec.tsx +91 -16
  26. package/src/Editor/Editor.tsx +3 -2
  27. package/src/EditorToolbar/Toolbar.tsx +2 -3
  28. package/src/EditorToolbar/Tools/Image/ImageButton.spec.tsx +12 -2
  29. package/src/EditorToolbar/Tools/Image/ImageButton.tsx +1 -1
  30. package/src/EditorToolbar/Tools/Link/LinkButton.spec.tsx +14 -2
  31. package/src/EditorToolbar/Tools/Lists/ListButtons.tsx +14 -0
  32. package/src/EditorToolbar/Tools/Lists/OrderedList/OrderListButton.spec.tsx +39 -0
  33. package/src/EditorToolbar/Tools/Lists/OrderedList/OrderedListButton.tsx +30 -0
  34. package/src/EditorToolbar/Tools/{UnorderedList → Lists/UnorderedList}/UnorderedList.spec.tsx +1 -1
  35. package/src/EditorToolbar/Tools/{UnorderedList → Lists/UnorderedList}/UnorderedListButton.tsx +1 -1
  36. package/src/Extensions/Extensions.ts +10 -2
  37. package/src/Extensions/FetchUrlExtension/FetchUrlExtension.ts +73 -0
  38. package/src/Extensions/ImageExtension/AssetImageExtension.spec.ts +2 -1
  39. package/src/Extensions/ImageExtension/AssetImageExtension.ts +5 -5
  40. package/src/Extensions/LinkExtension/AssetLinkExtension.spec.ts +3 -1
  41. package/src/Extensions/LinkExtension/AssetLinkExtension.ts +6 -5
  42. package/src/hooks/useFocus.ts +30 -7
  43. package/src/ui/Fields/MatrixAsset/MatrixAsset.spec.tsx +1 -0
  44. package/src/ui/Fields/MatrixAsset/MatrixAsset.tsx +2 -0
  45. package/src/ui/_typography.scss +10 -1
  46. package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.spec.ts +73 -0
  47. package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.ts +2 -1
  48. package/src/utils/getNodeNamesByGroup.spec.ts +1 -0
  49. package/tests/mockResourceBrowserContext.tsx +2 -2
  50. package/tests/renderWithContext.tsx +30 -1
  51. package/tests/renderWithEditor.tsx +18 -13
  52. package/lib/utils/resolveMatrixAssetUrl.d.ts +0 -1
  53. package/lib/utils/resolveMatrixAssetUrl.js +0 -10
  54. package/src/utils/resolveMatrixAssetUrl.spec.ts +0 -26
  55. package/src/utils/resolveMatrixAssetUrl.ts +0 -7
  56. /package/lib/EditorToolbar/Tools/{UnorderedList → Lists/UnorderedList}/UnorderedListButton.d.ts +0 -0
@@ -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[]> => Promise.resolve(resources),
14
- onRequestResource: (reference: ResourceReference): Promise<Resource | null> =>
15
- Promise.resolve(resources.find((resource) => resource.id === reference.resource) || null),
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
@@ -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
  ]
@@ -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)('remirror-theme formatted-text-editor', !editable && 'formatted-text-editor--is-disabled') },
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.bulletList && react_1.default.createElement(UnorderedListButton_1.default, null),
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),
@@ -53,7 +53,7 @@ const ImageButton = ({ inPopover = false }) => {
53
53
  insertAssetImage(assetImage);
54
54
  }
55
55
  };
56
- const handleSubmit = (data) => {
56
+ const handleSubmit = async (data) => {
57
57
  insertImageFromData(data);
58
58
  setShowModal(false);
59
59
  };
@@ -0,0 +1,2 @@
1
+ declare const ListButtons: () => JSX.Element;
2
+ export default ListButtons;
@@ -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,2 @@
1
+ declare const OrderedListButton: () => JSX.Element;
2
+ export default OrderedListButton;
@@ -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;
@@ -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("../../../ui/Button/Button"));
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;
@@ -7,6 +7,7 @@ export type AssetImageAttributes = {
7
7
  matrixAssetId: string;
8
8
  matrixIdentifier: string;
9
9
  matrixDomain: string;
10
+ url: string;
10
11
  };
11
12
  export declare class AssetImageExtension extends NodeExtension<AssetImageOptions> {
12
13
  get name(): NodeName.AssetImage;
@@ -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: (0, resolveMatrixAssetUrl_1.resolveMatrixAssetUrl)(String(matrixAssetId), String(matrixDomain)),
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
  };
@@ -6,6 +6,8 @@ export type AssetLinkAttributes = {
6
6
  matrixIdentifier: string;
7
7
  matrixDomain: string;
8
8
  target: LinkTarget;
9
+ href: string;
10
+ url: string;
9
11
  };
10
12
  export type AssetLinkOptions = {
11
13
  matrixDomain?: string;
@@ -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: (0, resolveMatrixAssetUrl_1.resolveMatrixAssetUrl)(String(matrixAssetId), String(matrixDomain)),
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,
@@ -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
- const isOutside = wrapperRef.current !== null && !wrapperRef.current.contains(event.relatedTarget);
12
- if (isOutside) {
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;
@@ -21,6 +21,7 @@ const MatrixAsset = ({ modalTitle, allowedTypes, value, onChange, ...props }) =>
21
21
  ...value,
22
22
  matrixIdentifier: reference?.source?.id,
23
23
  matrixAssetId: reference?.resource?.id,
24
+ url: reference?.resource?.url,
24
25
  },
25
26
  },
26
27
  });
@@ -19,8 +19,9 @@ const getNodeType = (node) => {
19
19
  img: 'image',
20
20
  pre: 'preformatted',
21
21
  p: 'paragraph',
22
- ul: 'bulletList',
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.40.1-alpha.9",
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.40.1-alpha.9",
24
- "@squiz/resource-browser": "1.40.1-alpha.9",
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": "c613b6cf103eb0e484153adecbef5d589bff872b"
78
+ "gitHead": "85be9c5f7ecf79f0037fb6124a122aab38ffaa59"
79
79
  }