docbrown/app/javascript/article-form/components/EditorBody.jsx
Andrew Bone 9ef1534d83
Add paste image (#10212)
Co-authored-by: Nick Taylor <nick@iamdeveloper.com>
Co-authored-by: ludwiczakpawel <ludwiczakpawel@gmail.com>
Co-authored-by: Nick Taylor <nick@dev.to>
Co-authored-by: Suzanne Aitchison <suzanne@forem.com>
2021-02-04 10:58:56 -05:00

102 lines
3 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 { handleImagePasted } from './pasteImageHelpers';
import {
handleImageDrop,
handleImageFailure,
onDragOver,
onDragExit,
} from './dragAndDropHelpers';
import { usePasteImage } from '@utilities/pasteImage';
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]
? image[0].name.replace(/\.[^.]+$/, '')
: 'alt text';
const markdownImageLink = `![${altText}](${links[0]})\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,
});
const setPasteElement = usePasteImage({
onPaste: handleImagePasted(
handleImageSuccess(textAreaRef),
handleImageFailure,
),
});
useEffect(() => {
if (textAreaRef.current) {
setElement(textAreaRef.current.base);
setPasteElement(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';