* Refactored drag n drop functionality to a hook and component. * Add the snackbar to the article editor. * Now you can drag and drop images in the post body content. * Cleaning up a few things. * Now post cover images can be dragged and dropped. * Removed unused empty function. * Added @testing-library/preact-hooks so that we can test hooks. * Some renaming, small refactor. * Added tests * Added more tests. * Added more tests. * Added message about dropping only one image in post body. * Added message about dropping only one image for cover image. * put onDrop into it's own meethod. * More tests. * Added some API documentation. * Updated editor help with drag and drop image help. * drag and drop styling * . * revert * Fixed broken test. Co-authored-by: Nick Taylor <nick@dev.to>
90 lines
2.6 KiB
JavaScript
90 lines
2.6 KiB
JavaScript
import { h } from 'preact';
|
|
import PropTypes from 'prop-types';
|
|
import Textarea from 'preact-textarea-autosize';
|
|
import { useEffect, useRef } from 'preact/hooks';
|
|
import { Toolbar } from './Toolbar';
|
|
import {
|
|
handleImageDrop,
|
|
handleImageFailure,
|
|
onDragOver,
|
|
onDragExit,
|
|
} from './dragAndDropHelpers';
|
|
import { useDragAndDrop } from '@utilities/dragAndDrop';
|
|
|
|
function handleImageSuccess(textAreaRef) {
|
|
return function (response) {
|
|
// Function is within the component to be able to access
|
|
// textarea ref.
|
|
const editableBodyElement = textAreaRef.current.base;
|
|
const { links, image } = response;
|
|
const altText = image[0].name.replace(/\.[^.]+$/, '');
|
|
const markdownImageLink = `\n`;
|
|
const { selectionStart, selectionEnd, value } = editableBodyElement;
|
|
const before = value.substring(0, selectionStart);
|
|
const after = value.substring(selectionEnd, value.length);
|
|
|
|
editableBodyElement.value = `${before + markdownImageLink} ${after}`;
|
|
editableBodyElement.selectionStart =
|
|
selectionStart + markdownImageLink.length;
|
|
editableBodyElement.selectionEnd = editableBodyElement.selectionStart;
|
|
|
|
// Dispatching a new event so that linkstate, https://github.com/developit/linkstate,
|
|
// the function used to create the onChange prop gets called correctly.
|
|
editableBodyElement.dispatchEvent(new Event('input'));
|
|
};
|
|
}
|
|
|
|
export const EditorBody = ({
|
|
onChange,
|
|
defaultValue,
|
|
switchHelpContext,
|
|
version,
|
|
}) => {
|
|
const textAreaRef = useRef(null);
|
|
const { setElement } = useDragAndDrop({
|
|
onDrop: handleImageDrop(
|
|
handleImageSuccess(textAreaRef),
|
|
handleImageFailure,
|
|
),
|
|
onDragOver,
|
|
onDragExit,
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (textAreaRef.current) {
|
|
setElement(textAreaRef.current.base);
|
|
}
|
|
});
|
|
|
|
return (
|
|
<div
|
|
data-testid="article-form__body"
|
|
className="crayons-article-form__body drop-area text-padding"
|
|
>
|
|
<Toolbar version={version} />
|
|
|
|
<Textarea
|
|
className="crayons-textfield crayons-textfield--ghost crayons-article-form__body__field"
|
|
id="article_body_markdown"
|
|
aria-label="Post Content"
|
|
placeholder="Write your post content here..."
|
|
value={defaultValue}
|
|
onInput={onChange}
|
|
onFocus={(_event) => {
|
|
switchHelpContext(_event);
|
|
}}
|
|
name="body_markdown"
|
|
ref={textAreaRef}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
EditorBody.propTypes = {
|
|
onChange: PropTypes.func.isRequired,
|
|
defaultValue: PropTypes.string.isRequired,
|
|
switchHelpContext: PropTypes.func.isRequired,
|
|
version: PropTypes.string.isRequired,
|
|
};
|
|
|
|
EditorBody.displayName = 'EditorBody';
|