@squiz/formatted-text-editor 1.35.1-alpha.2 → 1.35.1-alpha.20
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/App.tsx +15 -1
- package/lib/Editor/Editor.d.ts +4 -1
- package/lib/Editor/Editor.js +7 -4
- package/lib/EditorToolbar/Toolbar.d.ts +5 -1
- package/lib/EditorToolbar/Toolbar.js +4 -3
- package/lib/Extensions/UnsuportedExtension/UnsupportedNodeExtension.js +1 -1
- package/lib/hooks/useFocus.d.ts +6 -0
- package/lib/hooks/useFocus.js +18 -0
- package/lib/index.css +24 -0
- package/package.json +4 -4
- package/src/Editor/Editor.spec.tsx +50 -0
- package/src/Editor/Editor.tsx +16 -6
- package/src/Editor/_editor.scss +4 -0
- package/src/EditorToolbar/Toolbar.tsx +7 -3
- package/src/EditorToolbar/_toolbar.scss +15 -1
- package/src/Extensions/UnsuportedExtension/UnsupportedNodeExtension.spec.ts +2 -2
- package/src/Extensions/UnsuportedExtension/UnsupportedNodeExtension.tsx +1 -1
- package/src/hooks/useFocus.ts +21 -0
- package/src/ui/CollapseBox/_collapseBox.scss +1 -1
package/demo/App.tsx
CHANGED
@@ -3,8 +3,20 @@ import { Editor, remirrorNodeToSquizNode, squizNodeToRemirrorNode } from '../src
|
|
3
3
|
import { RemirrorEventListener, Extension } from '@remirror/core';
|
4
4
|
import ReactDiffViewer from 'react-diff-viewer-continued';
|
5
5
|
import { AppContext } from './AppContext';
|
6
|
+
import Button from '../src/ui/Button/Button';
|
7
|
+
import TextFieldsOutlinedIcon from '@mui/icons-material/TextFieldsOutlined';
|
8
|
+
import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined';
|
9
|
+
import { VerticalDivider } from '@remirror/react-components';
|
10
|
+
const ComponentHandlers = () => (
|
11
|
+
<div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '5px' }}>
|
12
|
+
<Button icon={<TextFieldsOutlinedIcon />} onClick={(x) => x} />
|
13
|
+
<VerticalDivider />
|
14
|
+
<Button icon={<DeleteOutlineOutlinedIcon />} onClick={(x) => x} />
|
15
|
+
</div>
|
16
|
+
);
|
6
17
|
|
7
18
|
function App() {
|
19
|
+
const [showChildren] = useState(false);
|
8
20
|
const [doc, setDoc] = useState('');
|
9
21
|
const [squizDoc, setSquizDoc] = useState('');
|
10
22
|
const [reconvertedDoc, setReconvertedDoc] = useState('');
|
@@ -41,7 +53,9 @@ function App() {
|
|
41
53
|
editable={editable}
|
42
54
|
content={`<p>Hello <a href="https://www.google.com"><strong>Mr Bean</strong></a>, nice to <a href="https://www.google.com">meet you</a>.<img src="https://media2.giphy.com/media/3o6ozsIxg5legYvggo/giphy.gif" height="150" width="200"/></p>`}
|
43
55
|
onChange={handleEditorChange}
|
44
|
-
|
56
|
+
>
|
57
|
+
{showChildren && <ComponentHandlers />}
|
58
|
+
</Editor>
|
45
59
|
</AppContext>
|
46
60
|
</div>
|
47
61
|
<h1>Document</h1>
|
package/lib/Editor/Editor.d.ts
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
+
import { ReactNode } from 'react';
|
1
2
|
import { RemirrorContentType, RemirrorEventListener, Extension } from '@remirror/core';
|
2
3
|
type EditorProps = {
|
3
4
|
content?: RemirrorContentType;
|
4
5
|
onChange?: RemirrorEventListener<Extension>;
|
5
6
|
editable?: boolean;
|
7
|
+
children?: ReactNode;
|
8
|
+
isFocused?: boolean;
|
6
9
|
};
|
7
|
-
declare const Editor: ({ content, editable, onChange }: EditorProps) => JSX.Element;
|
10
|
+
declare const Editor: ({ content, editable, onChange, children, isFocused }: EditorProps) => JSX.Element;
|
8
11
|
export default Editor;
|
package/lib/Editor/Editor.js
CHANGED
@@ -28,10 +28,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
29
29
|
const react_1 = __importStar(require("react"));
|
30
30
|
const react_2 = require("@remirror/react");
|
31
|
+
const clsx_1 = __importDefault(require("clsx"));
|
31
32
|
const EditorToolbar_1 = require("../EditorToolbar");
|
32
33
|
const EditorContext_1 = require("./EditorContext");
|
33
34
|
const Extensions_1 = require("../Extensions/Extensions");
|
34
|
-
const
|
35
|
+
const useFocus_1 = __importDefault(require("../hooks/useFocus"));
|
35
36
|
const WrappedEditor = () => {
|
36
37
|
const preventImagePaste = (0, react_1.useCallback)((event) => {
|
37
38
|
const { clipboardData } = event;
|
@@ -45,7 +46,7 @@ const WrappedEditor = () => {
|
|
45
46
|
(0, react_2.useEditorEvent)('paste', preventImagePaste);
|
46
47
|
return react_1.default.createElement(react_2.EditorComponent, null);
|
47
48
|
};
|
48
|
-
const Editor = ({ content, editable = true, onChange }) => {
|
49
|
+
const Editor = ({ content, editable = true, onChange, children, isFocused = false }) => {
|
49
50
|
const { manager, state, setState } = (0, react_2.useRemirror)({
|
50
51
|
extensions: (0, Extensions_1.createExtensions)((0, react_1.useContext)(EditorContext_1.EditorContext)),
|
51
52
|
content,
|
@@ -56,10 +57,12 @@ const Editor = ({ content, editable = true, onChange }) => {
|
|
56
57
|
setState(parameter.state);
|
57
58
|
onChange?.(parameter);
|
58
59
|
};
|
60
|
+
const { isEditorFocused, handleFocus, handleBlur } = (0, useFocus_1.default)(isFocused);
|
59
61
|
return (react_1.default.createElement("div", { className: "squiz-fte-scope" },
|
60
|
-
react_1.default.createElement("div", { className: (0, clsx_1.default)('remirror-theme formatted-text-editor', !editable && 'formatted-text-editor--is-disabled') },
|
62
|
+
react_1.default.createElement("div", { onBlur: handleBlur, onFocus: handleFocus, className: (0, clsx_1.default)('remirror-theme formatted-text-editor', !editable && 'formatted-text-editor--is-disabled') },
|
61
63
|
react_1.default.createElement(react_2.Remirror, { manager: manager, state: state, editable: editable, onChange: handleChange, placeholder: "Write something", label: "Text editor" },
|
62
|
-
editable && react_1.default.createElement(EditorToolbar_1.Toolbar,
|
64
|
+
editable && react_1.default.createElement(EditorToolbar_1.Toolbar, { isEditorFocused: isEditorFocused }),
|
65
|
+
children,
|
63
66
|
react_1.default.createElement(WrappedEditor, null),
|
64
67
|
editable && react_1.default.createElement(EditorToolbar_1.FloatingToolbar, null)))));
|
65
68
|
};
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.Toolbar = void 0;
|
7
7
|
const react_1 = __importDefault(require("react"));
|
8
8
|
const react_components_1 = require("@remirror/react-components");
|
9
|
+
const clsx_1 = __importDefault(require("clsx"));
|
9
10
|
const ItalicButton_1 = __importDefault(require("./Tools/Italic/ItalicButton"));
|
10
11
|
const UnderlineButton_1 = __importDefault(require("./Tools/Underline/UnderlineButton"));
|
11
12
|
const BoldButton_1 = __importDefault(require("./Tools/Bold/BoldButton"));
|
@@ -13,14 +14,14 @@ const TextAlignButtons_1 = __importDefault(require("./Tools/TextAlign/TextAlignB
|
|
13
14
|
const UndoButton_1 = __importDefault(require("./Tools/Undo/UndoButton"));
|
14
15
|
const RedoButton_1 = __importDefault(require("./Tools/Redo/RedoButton"));
|
15
16
|
const TextTypeDropdown_1 = __importDefault(require("./Tools/TextType/TextTypeDropdown"));
|
16
|
-
const hooks_1 = require("../hooks");
|
17
17
|
const LinkButton_1 = __importDefault(require("./Tools/Link/LinkButton"));
|
18
18
|
const ImageButton_1 = __importDefault(require("./Tools/Image/ImageButton"));
|
19
19
|
const RemoveLinkButton_1 = __importDefault(require("./Tools/Link/RemoveLinkButton"));
|
20
20
|
const ClearFormattingButton_1 = __importDefault(require("./Tools/ClearFormatting/ClearFormattingButton"));
|
21
|
-
const
|
21
|
+
const hooks_1 = require("../hooks");
|
22
|
+
const Toolbar = ({ isEditorFocused }) => {
|
22
23
|
const extensionNames = (0, hooks_1.useExtensionNames)();
|
23
|
-
return (react_1.default.createElement(react_components_1.Toolbar, { className:
|
24
|
+
return (react_1.default.createElement(react_components_1.Toolbar, { className: (0, clsx_1.default)('remirror-toolbar editor-toolbar', isEditorFocused === true ? 'show' : 'hide') },
|
24
25
|
extensionNames.history && (react_1.default.createElement(react_1.default.Fragment, null,
|
25
26
|
react_1.default.createElement(UndoButton_1.default, null),
|
26
27
|
react_1.default.createElement(RedoButton_1.default, null),
|
@@ -0,0 +1,18 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
const react_1 = require("react");
|
4
|
+
const useEditorFocus = (isFocused) => {
|
5
|
+
const [isEditorFocused, setIsEditorFocused] = (0, react_1.useState)(isFocused);
|
6
|
+
const handleFocus = (0, react_1.useCallback)(() => {
|
7
|
+
setIsEditorFocused(true);
|
8
|
+
}, []);
|
9
|
+
const handleBlur = (0, react_1.useCallback)(() => {
|
10
|
+
setIsEditorFocused(false);
|
11
|
+
}, []);
|
12
|
+
return {
|
13
|
+
isEditorFocused,
|
14
|
+
handleFocus,
|
15
|
+
handleBlur,
|
16
|
+
};
|
17
|
+
};
|
18
|
+
exports.default = useEditorFocus;
|
package/lib/index.css
CHANGED
@@ -835,6 +835,14 @@
|
|
835
835
|
.squiz-fte-scope .formatted-text-editor img {
|
836
836
|
display: inline;
|
837
837
|
}
|
838
|
+
.formatted-text-editor:has(.editor-toolbar.show, .show.squiz-fte-scope__floating-popover) {
|
839
|
+
--tw-shadow: 0 0 0 1px rgba(0,0,0,0.04), 0 1px 24px 12px rgba(0,0,0,0.12);
|
840
|
+
--tw-shadow-colored: 0 0 0 1px var(--tw-shadow-color), 0 1px 24px 12px var(--tw-shadow-color);
|
841
|
+
box-shadow:
|
842
|
+
var(--tw-ring-offset-shadow, 0 0 #0000),
|
843
|
+
var(--tw-ring-shadow, 0 0 #0000),
|
844
|
+
var(--tw-shadow);
|
845
|
+
}
|
838
846
|
.squiz-fte-scope .editor-toolbar,
|
839
847
|
.squiz-fte-scope__floating-popover {
|
840
848
|
border-bottom-width: 2px;
|
@@ -846,6 +854,7 @@
|
|
846
854
|
padding: 0.25rem;
|
847
855
|
display: flex;
|
848
856
|
justify-items: center;
|
857
|
+
flex-wrap: wrap;
|
849
858
|
}
|
850
859
|
.squiz-fte-scope .editor-toolbar > *:not(:first-child, .MuiDivider-root),
|
851
860
|
.squiz-fte-scope__floating-popover > *:not(:first-child, .MuiDivider-root) {
|
@@ -857,6 +866,8 @@
|
|
857
866
|
margin-bottom: -0.25rem;
|
858
867
|
margin-left: 0.25rem;
|
859
868
|
margin-right: 0.25rem;
|
869
|
+
margin-top: 0px;
|
870
|
+
margin-bottom: 0px;
|
860
871
|
border-width: 1px;
|
861
872
|
margin-right: 2px;
|
862
873
|
height: auto;
|
@@ -870,6 +881,18 @@
|
|
870
881
|
.squiz-fte-scope__floating-popover .squiz-fte-btn ~ .squiz-fte-btn {
|
871
882
|
margin-left: 2px;
|
872
883
|
}
|
884
|
+
.squiz-fte-scope .editor-toolbar.show,
|
885
|
+
.show.squiz-fte-scope__floating-popover {
|
886
|
+
max-height: 200px;
|
887
|
+
opacity: 1;
|
888
|
+
transition: max-height 0.3s ease, opacity 0.4s ease;
|
889
|
+
}
|
890
|
+
.squiz-fte-scope .editor-toolbar.hide,
|
891
|
+
.hide.squiz-fte-scope__floating-popover {
|
892
|
+
max-height: 0;
|
893
|
+
opacity: 0;
|
894
|
+
transition: max-height 0.3s ease, opacity 0.4s ease;
|
895
|
+
}
|
873
896
|
.squiz-fte-scope__floating-popover {
|
874
897
|
display: flex;
|
875
898
|
border-radius: 6px;
|
@@ -1041,6 +1064,7 @@
|
|
1041
1064
|
.squiz-fte-scope .collapse-box__label {
|
1042
1065
|
margin-left: 0.5rem;
|
1043
1066
|
margin-right: auto;
|
1067
|
+
text-align: left;
|
1044
1068
|
}
|
1045
1069
|
.squiz-fte-scope .collapse-box__icon {
|
1046
1070
|
--tw-text-opacity: 1;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@squiz/formatted-text-editor",
|
3
|
-
"version": "1.35.1-alpha.
|
3
|
+
"version": "1.35.1-alpha.20",
|
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.35.1-alpha.
|
24
|
-
"@squiz/resource-browser": "1.35.1-alpha.
|
23
|
+
"@squiz/dx-json-schema-lib": "1.35.1-alpha.20",
|
24
|
+
"@squiz/resource-browser": "1.35.1-alpha.20",
|
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": "396845eead32496e1a0297790fb3488c4dd85f2a"
|
79
79
|
}
|
@@ -5,7 +5,23 @@ import '@testing-library/jest-dom';
|
|
5
5
|
import { renderWithEditor } from '../../tests';
|
6
6
|
import ImageButton from '../EditorToolbar/Tools/Image/ImageButton';
|
7
7
|
|
8
|
+
const isEditorFocused = jest.fn().mockReturnValue(true);
|
9
|
+
const handleFocusMock = jest.fn();
|
10
|
+
const handleBlurMock = jest.fn();
|
11
|
+
jest.mock('../hooks/useFocus', () => ({
|
12
|
+
__esModule: true,
|
13
|
+
default: () => ({
|
14
|
+
isEditorFocused: isEditorFocused(),
|
15
|
+
handleFocus: handleFocusMock,
|
16
|
+
handleBlur: handleBlurMock,
|
17
|
+
}),
|
18
|
+
}));
|
19
|
+
|
8
20
|
describe('Formatted text editor', () => {
|
21
|
+
afterEach(() => {
|
22
|
+
jest.clearAllMocks();
|
23
|
+
});
|
24
|
+
|
9
25
|
it('Renders the text editor', () => {
|
10
26
|
render(<Editor />);
|
11
27
|
expect(screen.getByRole('textbox')).toBeInTheDocument();
|
@@ -311,4 +327,38 @@ describe('Formatted text editor', () => {
|
|
311
327
|
|
312
328
|
expect(buttonLabels).toEqual([]);
|
313
329
|
});
|
330
|
+
|
331
|
+
it('triggers handleFocus when editor is focused', async () => {
|
332
|
+
const { getByLabelText } = render(<Editor />);
|
333
|
+
const editorInput = getByLabelText('Text editor');
|
334
|
+
|
335
|
+
fireEvent.focus(editorInput);
|
336
|
+
|
337
|
+
expect(handleBlurMock).toHaveBeenCalledTimes(0);
|
338
|
+
expect(handleFocusMock).toHaveBeenCalledTimes(1);
|
339
|
+
});
|
340
|
+
|
341
|
+
it('triggers handleBlur when editor is blurred', () => {
|
342
|
+
const { getByLabelText } = render(<Editor />);
|
343
|
+
const editorInput = getByLabelText('Text editor');
|
344
|
+
|
345
|
+
fireEvent.blur(editorInput);
|
346
|
+
|
347
|
+
expect(handleBlurMock).toHaveBeenCalledTimes(1);
|
348
|
+
expect(handleFocusMock).toHaveBeenCalledTimes(0);
|
349
|
+
});
|
350
|
+
|
351
|
+
it('should apply hide class when focus hook returns false', () => {
|
352
|
+
isEditorFocused.mockReturnValue(false);
|
353
|
+
const { container } = render(<Editor />);
|
354
|
+
|
355
|
+
expect(container.querySelector('.hide')).toBeInTheDocument();
|
356
|
+
});
|
357
|
+
|
358
|
+
it('should apply show class when focus hook returns true', () => {
|
359
|
+
isEditorFocused.mockReturnValue(true);
|
360
|
+
const { container } = render(<Editor />);
|
361
|
+
|
362
|
+
expect(container.querySelector('.show')).toBeInTheDocument();
|
363
|
+
});
|
314
364
|
});
|
package/src/Editor/Editor.tsx
CHANGED
@@ -1,16 +1,19 @@
|
|
1
|
-
import React, { useContext, useCallback } from 'react';
|
1
|
+
import React, { useContext, useCallback, ReactNode } from 'react';
|
2
2
|
import { EditorComponent, Remirror, useRemirror, useEditorEvent } from '@remirror/react';
|
3
3
|
import { RemirrorContentType, RemirrorEventListener, Extension } from '@remirror/core';
|
4
|
+
import { ClipboardEventHandler } from '@remirror/extension-events/dist-types/events-extension';
|
5
|
+
import clsx from 'clsx';
|
4
6
|
import { Toolbar, FloatingToolbar } from '../EditorToolbar';
|
5
7
|
import { EditorContext } from './EditorContext';
|
6
8
|
import { createExtensions } from '../Extensions/Extensions';
|
7
|
-
import
|
8
|
-
import { ClipboardEventHandler } from '@remirror/extension-events/dist-types/events-extension';
|
9
|
+
import useEditorFocus from '../hooks/useFocus';
|
9
10
|
|
10
11
|
type EditorProps = {
|
11
12
|
content?: RemirrorContentType;
|
12
13
|
onChange?: RemirrorEventListener<Extension>;
|
13
14
|
editable?: boolean;
|
15
|
+
children?: ReactNode;
|
16
|
+
isFocused?: boolean;
|
14
17
|
};
|
15
18
|
|
16
19
|
const WrappedEditor = () => {
|
@@ -29,7 +32,7 @@ const WrappedEditor = () => {
|
|
29
32
|
return <EditorComponent />;
|
30
33
|
};
|
31
34
|
|
32
|
-
const Editor = ({ content, editable = true, onChange }: EditorProps) => {
|
35
|
+
const Editor = ({ content, editable = true, onChange, children, isFocused = false }: EditorProps) => {
|
33
36
|
const { manager, state, setState } = useRemirror({
|
34
37
|
extensions: createExtensions(useContext(EditorContext)),
|
35
38
|
content,
|
@@ -42,9 +45,15 @@ const Editor = ({ content, editable = true, onChange }: EditorProps) => {
|
|
42
45
|
onChange?.(parameter);
|
43
46
|
};
|
44
47
|
|
48
|
+
const { isEditorFocused, handleFocus, handleBlur } = useEditorFocus(isFocused);
|
49
|
+
|
45
50
|
return (
|
46
51
|
<div className="squiz-fte-scope">
|
47
|
-
<div
|
52
|
+
<div
|
53
|
+
onBlur={handleBlur}
|
54
|
+
onFocus={handleFocus}
|
55
|
+
className={clsx('remirror-theme formatted-text-editor', !editable && 'formatted-text-editor--is-disabled')}
|
56
|
+
>
|
48
57
|
<Remirror
|
49
58
|
manager={manager}
|
50
59
|
state={state}
|
@@ -53,7 +62,8 @@ const Editor = ({ content, editable = true, onChange }: EditorProps) => {
|
|
53
62
|
placeholder="Write something"
|
54
63
|
label="Text editor"
|
55
64
|
>
|
56
|
-
{editable && <Toolbar />}
|
65
|
+
{editable && <Toolbar isEditorFocused={isEditorFocused} />}
|
66
|
+
{children}
|
57
67
|
<WrappedEditor />
|
58
68
|
{editable && <FloatingToolbar />}
|
59
69
|
</Remirror>
|
package/src/Editor/_editor.scss
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import { Toolbar as RemirrorToolbar, VerticalDivider } from '@remirror/react-components';
|
3
|
+
import clsx from 'clsx';
|
3
4
|
import ItalicButton from './Tools/Italic/ItalicButton';
|
4
5
|
import UnderlineButton from './Tools/Underline/UnderlineButton';
|
5
6
|
import BoldButton from './Tools/Bold/BoldButton';
|
@@ -7,17 +8,20 @@ import TextAlignButtons from './Tools/TextAlign/TextAlignButtons';
|
|
7
8
|
import UndoButton from './Tools/Undo/UndoButton';
|
8
9
|
import RedoButton from './Tools/Redo/RedoButton';
|
9
10
|
import TextTypeDropdown from './Tools/TextType/TextTypeDropdown';
|
10
|
-
import { useExtensionNames } from '../hooks';
|
11
11
|
import LinkButton from './Tools/Link/LinkButton';
|
12
12
|
import ImageButton from './Tools/Image/ImageButton';
|
13
13
|
import RemoveLinkButton from './Tools/Link/RemoveLinkButton';
|
14
14
|
import ClearFormattingButton from './Tools/ClearFormatting/ClearFormattingButton';
|
15
|
+
import { useExtensionNames } from '../hooks';
|
15
16
|
|
16
|
-
|
17
|
+
type ToolbarProps = {
|
18
|
+
isEditorFocused: boolean;
|
19
|
+
};
|
20
|
+
export const Toolbar = ({ isEditorFocused }: ToolbarProps) => {
|
17
21
|
const extensionNames = useExtensionNames();
|
18
22
|
|
19
23
|
return (
|
20
|
-
<RemirrorToolbar className=
|
24
|
+
<RemirrorToolbar className={clsx('remirror-toolbar editor-toolbar', isEditorFocused === true ? 'show' : 'hide')}>
|
21
25
|
{extensionNames.history && (
|
22
26
|
<>
|
23
27
|
<UndoButton />
|
@@ -3,20 +3,34 @@
|
|
3
3
|
|
4
4
|
display: flex;
|
5
5
|
justify-items: center;
|
6
|
+
flex-wrap: wrap;
|
6
7
|
|
7
8
|
> *:not(:first-child, .MuiDivider-root) {
|
8
9
|
margin: 0 0 0 2px;
|
9
10
|
}
|
10
11
|
|
11
12
|
.MuiDivider-root {
|
12
|
-
@apply -my-1 mx-1 border;
|
13
|
+
@apply -my-1 mx-1 border mt-0 mb-0;
|
13
14
|
margin-right: 2px;
|
14
15
|
height: auto;
|
15
16
|
}
|
17
|
+
|
16
18
|
.squiz-fte-btn {
|
17
19
|
@apply p-1 font-bold;
|
18
20
|
~ .squiz-fte-btn {
|
19
21
|
margin-left: 2px;
|
20
22
|
}
|
21
23
|
}
|
24
|
+
|
25
|
+
&.show {
|
26
|
+
max-height: 200px;
|
27
|
+
opacity: 1;
|
28
|
+
transition: max-height 0.3s ease, opacity 0.4s ease;
|
29
|
+
}
|
30
|
+
|
31
|
+
&.hide {
|
32
|
+
max-height: 0;
|
33
|
+
opacity: 0;
|
34
|
+
transition: max-height 0.3s ease, opacity 0.4s ease;
|
35
|
+
}
|
22
36
|
}
|
@@ -35,7 +35,7 @@ describe('UnsupportedNodeExtension', () => {
|
|
35
35
|
const nodeSpec = extension.createNodeSpec(extra, override);
|
36
36
|
|
37
37
|
expect(nodeSpec.selectable).toBe(true);
|
38
|
-
expect(nodeSpec.draggable).toBe(
|
38
|
+
expect(nodeSpec.draggable).toBe(false);
|
39
39
|
expect(nodeSpec.atom).toBe(true);
|
40
40
|
expect(nodeSpec.inline).toBe(true);
|
41
41
|
expect(nodeSpec.attrs).toEqual({ originalNode: {}, errorMessage: {} });
|
@@ -131,7 +131,7 @@ describe('UnsupportedNodeExtension', () => {
|
|
131
131
|
});
|
132
132
|
|
133
133
|
expect(getHtmlContent()).toBe(
|
134
|
-
'<span class="unsupported-node-node-view-wrapper" originalnode="null" errormessage="null" data-unsupported-node="{"originalNode":null,"errorMessage":null}"
|
134
|
+
'<span class="unsupported-node-node-view-wrapper" originalnode="null" errormessage="null" data-unsupported-node="{"originalNode":null,"errorMessage":null}"><div class="collapse-box" contenteditable="false"><button class="collapse-box__header" type="button"><svg class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium collapse-box__icon--warning css-i4bv87-MuiSvgIcon-root" focusable="false" aria-hidden="true" viewBox="0 0 24 24" data-testid="MotionPhotosOffOutlinedIcon"><path d="M2.81 2.81 1.39 4.22l2.27 2.27C2.61 8.07 2 9.96 2 12c0 5.52 4.48 10 10 10 2.04 0 3.93-.61 5.51-1.66l2.27 2.27 1.41-1.42L2.81 2.81zM12 20c-4.41 0-8-3.59-8-8 0-1.48.41-2.86 1.12-4.06l10.93 10.94C14.86 19.59 13.48 20 12 20zm0-16c4.41 0 8 3.59 8 8 0 1.48-.41 2.86-1.12 4.05l1.45 1.45C21.39 15.93 22 14.04 22 12c0-5.52-4.48-10-10-10-2.04 0-3.93.61-5.51 1.66l1.45 1.45C9.14 4.41 10.52 4 12 4z"></path></svg><div class="collapse-box__label">This section cannot be displayed here due to unsupported HTML elements. The front-end view of your page won’t be affected.</div><svg class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-i4bv87-MuiSvgIcon-root" focusable="false" aria-hidden="true" viewBox="0 0 24 24" data-testid="UnfoldLessOutlinedIcon"><path d="M7.41 18.59 8.83 20 12 16.83 15.17 20l1.41-1.41L12 14l-4.59 4.59zm9.18-13.18L15.17 4 12 7.17 8.83 4 7.41 5.41 12 10l4.59-4.59z"></path></svg></button><div class="collapse-box__content" hidden="" data-testid="content"><br>null</div></div></span>',
|
135
135
|
);
|
136
136
|
});
|
137
137
|
});
|
@@ -30,7 +30,7 @@ export class UnsupportedNodeExtension extends NodeExtension {
|
|
30
30
|
createNodeSpec(extra: ApplySchemaAttributes, override: NodeSpecOverride): NodeExtensionSpec {
|
31
31
|
return {
|
32
32
|
selectable: false,
|
33
|
-
draggable:
|
33
|
+
draggable: false,
|
34
34
|
atom: true,
|
35
35
|
inline: true,
|
36
36
|
...override,
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { useState, useCallback } from 'react';
|
2
|
+
|
3
|
+
const useEditorFocus = (isFocused: boolean) => {
|
4
|
+
const [isEditorFocused, setIsEditorFocused] = useState(isFocused);
|
5
|
+
|
6
|
+
const handleFocus = useCallback(() => {
|
7
|
+
setIsEditorFocused(true);
|
8
|
+
}, []);
|
9
|
+
|
10
|
+
const handleBlur = useCallback(() => {
|
11
|
+
setIsEditorFocused(false);
|
12
|
+
}, []);
|
13
|
+
|
14
|
+
return {
|
15
|
+
isEditorFocused,
|
16
|
+
handleFocus,
|
17
|
+
handleBlur,
|
18
|
+
};
|
19
|
+
};
|
20
|
+
|
21
|
+
export default useEditorFocus;
|