UNPKG

phx-react

Version:

PHX REACT

177 lines • 7.63 kB
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; import { $wrapNodeInElement, mergeRegister } from '@lexical/utils'; import { $createParagraphNode, $createRangeSelection, $getSelection, $insertNodes, $isNodeSelection, $isRootOrShadowRoot, $setSelection, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_LOW, createCommand, DRAGOVER_COMMAND, DRAGSTART_COMMAND, DROP_COMMAND, } from 'lexical'; import { useEffect, useState } from 'react'; import * as React from 'react'; import { $createImageNode, $isImageNode, ImageNode } from '../../nodes/ImageNode'; import { CAN_USE_DOM } from '../../shared/canUseDOM'; import Button from '../../ui/Button'; import { DialogActions } from '../../ui/Dialog'; import TextInput from '../../ui/TextInput'; import { PHXModal } from '../../../Modal'; import { PHXInput } from '../../../Input'; import { PHXUploadFile } from '../../../UploadFile'; const getDOMSelection = (targetWindow) => CAN_USE_DOM ? (targetWindow || window).getSelection() : null; export const INSERT_IMAGE_COMMAND = createCommand('INSERT_IMAGE_COMMAND'); export function InsertImageUriDialogBody({ onClick }) { const [src, setSrc] = useState(''); const [altText, setAltText] = useState(''); const isDisabled = src === ''; return (React.createElement(React.Fragment, null, React.createElement(TextInput, { "data-test-id": 'image-modal-url-input', label: 'Image URL', onChange: setSrc, placeholder: 'i.e. https://source.unsplash.com/random', value: src }), React.createElement(TextInput, { "data-test-id": 'image-modal-alt-text-input', label: 'Alt Text', onChange: setAltText, placeholder: 'Random unsplash image', value: altText }), React.createElement(DialogActions, null, React.createElement(Button, { "data-test-id": 'image-modal-confirm-btn', disabled: isDisabled, onClick: () => onClick({ altText, src }) }, "Confirm")))); } export function InsertImageModal({ activeEditor, setShow, show, }) { const [fileName, setFileName] = useState(''); const [cdnLink, setCdnLink] = useState(''); let altText = 'photo'; const onHide = () => { setShow(false); setCdnLink(''); setFileName(''); }; const handleListenUpload = (fileUpload, linkCdn) => { setFileName(fileUpload.name); setCdnLink(linkCdn[0]); }; const handleSubmit = () => { activeEditor.dispatchCommand(INSERT_IMAGE_COMMAND, { altText, src: cdnLink }); onHide(); }; return (React.createElement(PHXModal, { onHide: onHide, onPrimaryClick: handleSubmit, show: show, title: 'Insert Image' }, React.createElement("div", { className: 'space-y-4' }, React.createElement(PHXInput, { defaultValue: altText, label: 'Alt Text', onChange: (e) => (altText = e.target.value) }), React.createElement(PHXUploadFile, { apiCdnUpload: '/api/cdn-upload', basePath: '', defaultLink: [cdnLink], fileName: fileName, fileType: 'image', handleListenUpload: handleListenUpload, inCard: false, label: 'Image upload', moduleId: 'insert-editor-image', oneImg: true, projectId: 'phenikaa', titleHeaderAction: '' })))); } export default function ImagesPlugin({ captionsEnabled }) { const [editor] = useLexicalComposerContext(); useEffect(() => { if (!editor.hasNodes([ImageNode])) { throw new Error('ImagesPlugin: ImageNode not registered on editor'); } return mergeRegister(editor.registerCommand(INSERT_IMAGE_COMMAND, (payload) => { const imageNode = $createImageNode(payload); $insertNodes([imageNode]); if ($isRootOrShadowRoot(imageNode.getParentOrThrow())) { $wrapNodeInElement(imageNode, $createParagraphNode).selectEnd(); } return true; }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(DRAGSTART_COMMAND, (event) => onDragStart(event), COMMAND_PRIORITY_HIGH), editor.registerCommand(DRAGOVER_COMMAND, (event) => onDragover(event), COMMAND_PRIORITY_LOW), editor.registerCommand(DROP_COMMAND, (event) => onDrop(event, editor), COMMAND_PRIORITY_HIGH)); }, [captionsEnabled, editor]); return null; } const TRANSPARENT_IMAGE = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; function onDragStart(event) { const img = document.createElement('img'); img.src = TRANSPARENT_IMAGE; const node = getImageNodeInSelection(); if (!node) { return false; } const dataTransfer = event.dataTransfer; if (!dataTransfer) { return false; } dataTransfer.setData('text/plain', '_'); dataTransfer.setDragImage(img, 0, 0); dataTransfer.setData('application/x-lexical-drag', JSON.stringify({ data: { altText: node.__altText, caption: node.__caption, height: node.__height, key: node.getKey(), maxWidth: node.__maxWidth, position: node.__position, showCaption: node.__showCaption, src: node.__src, width: node.__width, }, type: 'image', })); return true; } function onDragover(event) { const node = getImageNodeInSelection(); if (!node) { return false; } if (!canDropImage(event)) { event.preventDefault(); } return true; } function onDrop(event, editor) { const node = getImageNodeInSelection(); if (!node) { return false; } const data = getDragImageData(event); if (!data) { return false; } event.preventDefault(); if (canDropImage(event)) { const range = getDragSelection(event); node.remove(); const rangeSelection = $createRangeSelection(); if (range !== null && range !== undefined) { rangeSelection.applyDOMRange(range); } $setSelection(rangeSelection); editor.dispatchCommand(INSERT_IMAGE_COMMAND, data); } return true; } function getImageNodeInSelection() { const selection = $getSelection(); if (!$isNodeSelection(selection)) { return null; } const nodes = selection.getNodes(); const node = nodes[0]; return $isImageNode(node) ? node : null; } function getDragImageData(event) { var _a; const dragData = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData('application/x-lexical-drag'); if (!dragData) { return null; } const { data, type } = JSON.parse(dragData); if (type !== 'image') { return null; } return data; } function canDropImage(event) { const target = event.target; return !!(target && target instanceof HTMLElement && !target.closest('code, span.editor-image') && target.parentElement && target.parentElement.closest('div.ContentEditable__root')); } function getDragSelection(event) { let range; const target = event.target; const targetWindow = target == null ? null : target.nodeType === 9 ? target.defaultView : target.ownerDocument.defaultView; const domSelection = getDOMSelection(targetWindow); if (document.caretRangeFromPoint) { range = document.caretRangeFromPoint(event.clientX, event.clientY); } else if (event.rangeParent && domSelection !== null) { domSelection.collapse(event.rangeParent, event.rangeOffset || 0); range = domSelection.getRangeAt(0); } else { throw Error(`Cannot get the selection when dragging`); } return range; } //# sourceMappingURL=index.js.map