@squiz/formatted-text-editor 1.35.1-alpha.2 → 1.35.1-alpha.21

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 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>
@@ -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;
@@ -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 clsx_1 = __importDefault(require("clsx"));
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, null),
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
  };
@@ -1 +1,5 @@
1
- export declare const Toolbar: () => JSX.Element;
1
+ type ToolbarProps = {
2
+ isEditorFocused: boolean;
3
+ };
4
+ export declare const Toolbar: ({ isEditorFocused }: ToolbarProps) => JSX.Element;
5
+ export {};
@@ -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 Toolbar = () => {
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: "remirror-toolbar editor-toolbar" },
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),
@@ -24,7 +24,7 @@ let UnsupportedNodeExtension = class UnsupportedNodeExtension extends core_1.Nod
24
24
  createNodeSpec(extra, override) {
25
25
  return {
26
26
  selectable: false,
27
- draggable: true,
27
+ draggable: false,
28
28
  atom: true,
29
29
  inline: true,
30
30
  ...override,
@@ -0,0 +1,6 @@
1
+ declare const useEditorFocus: (isFocused: boolean) => {
2
+ isEditorFocused: boolean;
3
+ handleFocus: () => void;
4
+ handleBlur: () => void;
5
+ };
6
+ export default useEditorFocus;
@@ -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.2",
3
+ "version": "1.35.1-alpha.21",
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.2",
24
- "@squiz/resource-browser": "1.35.1-alpha.2",
23
+ "@squiz/dx-json-schema-lib": "1.35.1-alpha.21",
24
+ "@squiz/resource-browser": "1.35.1-alpha.21",
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": "960d69b1a18d417be13a9c3d4ba17b055bb4dd54"
78
+ "gitHead": "d2b4803d61cfb55aad8d3876df8cecc369c54bd4"
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
  });
@@ -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 clsx from 'clsx';
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 className={clsx('remirror-theme formatted-text-editor', !editable && 'formatted-text-editor--is-disabled')}>
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>
@@ -48,4 +48,8 @@
48
48
  img {
49
49
  display: inline;
50
50
  }
51
+
52
+ &:has(.editor-toolbar.show) {
53
+ @apply shadow-lg;
54
+ }
51
55
  }
@@ -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
- export const Toolbar = () => {
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="remirror-toolbar editor-toolbar">
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(true);
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="{&quot;originalNode&quot;:null,&quot;errorMessage&quot;:null}" draggable="true"><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>',
134
+ '<span class="unsupported-node-node-view-wrapper" originalnode="null" errormessage="null" data-unsupported-node="{&quot;originalNode&quot;:null,&quot;errorMessage&quot;: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: true,
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;
@@ -6,7 +6,7 @@
6
6
  }
7
7
 
8
8
  &__label {
9
- @apply ml-2 mr-auto;
9
+ @apply ml-2 mr-auto text-left;
10
10
  }
11
11
 
12
12
  &__icon {