diff --git a/admin/src/components/Input/components/CKEReact.jsx b/admin/src/components/Input/components/CKEReact.jsx
new file mode 100644
index 0000000..cb02925
--- /dev/null
+++ b/admin/src/components/Input/components/CKEReact.jsx
@@ -0,0 +1,79 @@
+import React, { useRef, useState } from 'react';
+import { useField } from '@strapi/strapi/admin';
+import { Box } from '@strapi/design-system';
+import styled from 'styled-components';
+import { ClassicEditor } from 'ckeditor5';
+import { CKEditor } from '@ckeditor/ckeditor5-react';
+import 'ckeditor5/ckeditor5.css';
+
+export const CKEReact = ({
+ name,
+ disabled,
+ maxLength,
+ preset,
+ setEditorInstance,
+}) => {
+ const { onChange: fieldOnChange, value, error } = useField(name);
+
+ const [lengthMax, setLengthMax] = useState(false);
+
+ const wordCounter = useRef(null);
+
+ const handleCounter = (number) => setLengthMax(number > maxLength);
+
+ const hasWordCountPlugin = Boolean(preset.editorConfig.WordCountPlugin);
+
+ const onEditorReady = (editor) => {
+ if (hasWordCountPlugin) {
+ const wordCountPlugin = editor.plugins.get('WordCount');
+ wordCountPlugin.on('update', (evt, stats) =>
+ handleCounter(stats.characters)
+ );
+ const wordCountWrapper = wordCounter.current;
+ wordCountWrapper?.appendChild(wordCountPlugin.wordCountContainer);
+ }
+
+ if (editor.plugins.has('ImageUploadEditing')) {
+ editor.plugins
+ .get('ImageUploadEditing')
+ .on('uploadComplete', (evt, { data, imageElement }) =>
+ editor.model.change((writer) =>
+ writer.setAttribute('alt', data.alt, imageElement)
+ )
+ );
+ }
+
+ setEditorInstance(editor);
+ };
+
+ const onEditorChange = (event, editor) => {
+ const data = editor.getData();
+ fieldOnChange({ target: { name, value: data } });
+ };
+
+ return (
+ <>
+
+ {hasWordCountPlugin && (
+
+ )}
+ >
+ );
+};
+
+const WordCounterBox = styled(Box)`
+ display: flex;
+ width: 100%;
+ justify-content: flex-end;
+ align-items: center;
+`;
diff --git a/admin/src/components/Input/components/Editor.jsx b/admin/src/components/Input/components/Editor.jsx
index 5694727..1a1643a 100644
--- a/admin/src/components/Input/components/Editor.jsx
+++ b/admin/src/components/Input/components/Editor.jsx
@@ -1,20 +1,14 @@
-import React, { useEffect, useRef, useState } from 'react';
-import PropTypes from 'prop-types';
+import React, { useEffect, useState } from 'react';
+import { Loader } from '@strapi/design-system';
+import { Box } from '@strapi/design-system';
import styled from 'styled-components';
-import { CKEditor } from '@ckeditor/ckeditor5-react';
-import { ClassicEditor } from 'ckeditor5';
-import { Box, Loader } from '@strapi/design-system';
-import { useField } from '@strapi/strapi/admin';
-import 'ckeditor5/ckeditor5.css';
+import { CKEReact } from './CKEReact';
+import { EditorLayout } from './EditorLayout';
import { MediaLib } from './MediaLib';
import { getConfiguredPreset } from '../config';
import { GlobalStyling } from './GlobalStyling';
-const Wrapper = styled('div')`
- ${({ styles }) => styles}
-`;
-
export const Editor = ({
name,
disabled,
@@ -22,27 +16,24 @@ export const Editor = ({
maxLength,
placeholder,
}) => {
- const { onChange, value } = useField(name);
-
- const [editorInstance, setEditorInstance] = useState(false);
-
const [mediaLibVisible, setMediaLibVisible] = useState(false);
-
+ const [editorInstance, setEditorInstance] = useState(false);
const [preset, setPreset] = useState(null);
- const [lengthMax, setLengthMax] = useState(false);
-
- const wordCounter = useRef(null);
+ const toggleMediaLib = () => setMediaLibVisible((prev) => !prev);
- const handleToggleMediaLib = () => setMediaLibVisible((prev) => !prev);
+ const handleChangeAssets = (newElems) => {
+ const viewFragment = editorInstance.data.processor.toView(newElems);
+ const modelFragment = editorInstance.data.toModel(viewFragment);
+ editorInstance.model.insertContent(modelFragment);
- const handleCounter = (number) =>
- number > maxLength ? setLengthMax(true) : setLengthMax(false);
+ toggleMediaLib();
+ };
useEffect(() => {
(async () => {
const currentPreset = await getConfiguredPreset(presetName, {
- toggleMediaLib: handleToggleMediaLib,
+ toggleMediaLib: toggleMediaLib,
strapiFieldPlaceholder: placeholder,
});
@@ -50,89 +41,39 @@ export const Editor = ({
})();
}, []);
+ if (!preset) {
+ return (
+
+ Loading...
+
+ );
+ }
+
return (
<>
- {preset && }
-
- {!preset && (
-
- Loading...
-
- )}
- {preset && (
- <>
- {
- if (preset.editorConfig.WordCountPlugin) {
- const wordCountPlugin = editor.plugins.get('WordCount');
- wordCountPlugin.on('update', (evt, stats) =>
- handleCounter(stats.characters)
- );
- const wordCountWrapper = wordCounter.current;
- wordCountWrapper?.appendChild(
- wordCountPlugin.wordCountContainer
- );
- }
-
- if (editor.plugins.has('ImageUploadEditing')) {
- editor.plugins
- .get('ImageUploadEditing')
- .on('uploadComplete', (evt, { data, imageElement }) =>
- editor.model.change((writer) =>
- writer.setAttribute('alt', data.alt, imageElement)
- )
- );
- }
-
- setEditorInstance(editor);
- }}
- onChange={(event, editor) => {
- const data = editor.getData();
- onChange({ target: { name, value: data } });
- }}
- />
-
- {preset.editorConfig.WordCountPlugin && (
-
- {!editorInstance && Loading...}
-
- )}
- >
- )}
-
+
+
+
+
+
>
);
};
-Editor.propTypes = {
- name: PropTypes.string.isRequired,
- disabled: PropTypes.bool,
- presetName: PropTypes.string.isRequired,
- maxLength: PropTypes.number,
- placeholder: PropTypes.string,
-};
-
-const CounterLoaderBox = styled(Box)`
- display: flex;
- width: 100%;
- justify-content: flex-end;
- align-items: center;
-`;
const LoaderBox = styled(Box)`
display: flex;
- height: 200px;
- width: 100%;
justify-content: center;
align-items: center;
-`;
+ height: 200px;
+ width: 100%;
+`;
\ No newline at end of file
diff --git a/admin/src/components/Input/components/EditorLayout.jsx b/admin/src/components/Input/components/EditorLayout.jsx
new file mode 100644
index 0000000..6e1d97e
--- /dev/null
+++ b/admin/src/components/Input/components/EditorLayout.jsx
@@ -0,0 +1,106 @@
+import React, { useEffect, useState } from 'react';
+import { Box, Flex, IconButton, FocusTrap, Portal } from '@strapi/design-system';
+import { Expand, Collapse } from '@strapi/icons';
+import styled from 'styled-components';
+
+export const EditorLayout = ({ children, presetStyles }) => {
+ const [isExpandedMode, setIsExpandedMode] = useState(false);
+
+ const handleToggleExpand = () => setIsExpandedMode(true);
+ const handleOnCollapse = () => setIsExpandedMode(false);
+
+ useEffect(() => {
+ if (isExpandedMode) {
+ document.body.classList.add('lock-body-scroll');
+ }
+
+ return () => {
+ document.body.classList.remove('lock-body-scroll');
+ };
+ }, [isExpandedMode]);
+
+ if (isExpandedMode) {
+ return (
+
+
+
+ e.stopPropagation()}
+ position="relative"
+ >
+
+
+ {children}
+
+
+
+
+
+
+
+
+
+ );
+ }
+
+ return (
+
+ {children}
+
+
+
+
+ );
+};
+
+const EditorWrapper = styled('div')`
+ position: relative;
+ width: 100%;
+ height: 100%;
+
+ ${({ $presetStyles }) => $presetStyles}
+`;
+
+const Backdrop = styled(Flex)`
+ // Background with 20% opacity
+ background: ${({ theme }) => `${theme.colors.neutral800}1F`};
+`;
+
+const ExpandButton = styled(IconButton)`
+ position: absolute;
+ bottom: 1.4rem;
+ right: 1.2rem;
+ z-index: 2;
+`;
+
+const CollapseButton = styled(IconButton)`
+ position: absolute;
+ bottom: 2.5rem;
+ right: 1.2rem;
+ z-index: 2;
+`;
+
+const FullScreenBox = styled(Box)`
+ max-width: var(--ck-editor-full-screen-box-max-width);
+`
\ No newline at end of file
diff --git a/admin/src/components/Input/components/MediaLib.jsx b/admin/src/components/Input/components/MediaLib.jsx
index 5eb4e05..2eab61f 100644
--- a/admin/src/components/Input/components/MediaLib.jsx
+++ b/admin/src/components/Input/components/MediaLib.jsx
@@ -1,16 +1,15 @@
import React from 'react';
-import PropTypes from 'prop-types';
import { useStrapiApp } from '@strapi/strapi/admin';
import { prefixFileUrlWithBackendUrl } from '../../../utils/prefixFileUrlWithBackendUrl'
-export const MediaLib = ({ isOpen = false, onToggle = () => {}, editor }) => {
+export const MediaLib = ({ isOpen = false, toggle, handleChangeAssets }) => {
const components = useStrapiApp('MediaLib', ({ components }) => components);
const MediaLibraryDialog = components['media-library'];
- const handleChangeAssets = (assets) => {
- let newValue = '';
+ const getNewElems = (assets) => {
+ let newElems = '';
assets.map(({ name, url, alt, formats, mime, width, height }) => {
if (mime.includes('image')) {
@@ -18,25 +17,21 @@ export const MediaLib = ({ isOpen = false, onToggle = () => {}, editor }) => {
let set = '';
let keys = Object.keys(formats).sort((a, b) => formats[a].width - formats[b].width);
keys.map((k) => (set += prefixFileUrlWithBackendUrl(formats[k].url) +` ${formats[k].width}w,`));
- newValue += ``;
+ newElems += ``;
} else {
- newValue += ``;
+ newElems += ``;
}
} else if (mime.includes('video')) {
- newValue += `
+ newElems += `
`;
} else {
- newValue += `${name || 'Open document'}`;
+ newElems += `${name || 'Open document'}`;
}
});
- const viewFragment = editor.data.processor.toView(newValue);
- const modelFragment = editor.data.toModel(viewFragment);
- editor.model.insertContent(modelFragment);
-
- onToggle();
+ return newElems;
};
const handleSelectAssets = (files) => {
@@ -50,7 +45,9 @@ export const MediaLib = ({ isOpen = false, onToggle = () => {}, editor }) => {
height: f.height,
}));
- handleChangeAssets(formattedFiles);
+ const newElems = getNewElems(formattedFiles);
+
+ handleChangeAssets(newElems);
};
if (!isOpen) {
@@ -59,13 +56,8 @@ export const MediaLib = ({ isOpen = false, onToggle = () => {}, editor }) => {
return (
);
-};
-
-MediaLib.propTypes = {
- isOpen: PropTypes.bool,
- onToggle: PropTypes.func,
};
\ No newline at end of file
diff --git a/admin/src/components/Input/index.jsx b/admin/src/components/Input/index.jsx
index 85e545b..befd913 100644
--- a/admin/src/components/Input/index.jsx
+++ b/admin/src/components/Input/index.jsx
@@ -1,28 +1,28 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Field, Flex } from '@strapi/design-system';
+import { useField } from '@strapi/admin/strapi-admin';
import { Editor } from './components/Editor';
const Input = ({
name,
attribute,
- value = '',
labelAction = null,
label,
disabled = false,
- error = null,
required = false,
- hint = '',
+ hint,
placeholder,
}) => {
const { preset, maxLengthCharacters, ...options } = attribute.options;
+ const field = useField(name);
return (
@@ -31,7 +31,6 @@ const Input = ({