UNPKG

mui-tiptap

Version:

A Material-UI (MUI) styled WYSIWYG rich text editor, using Tiptap

87 lines (86 loc) 6.14 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { Button, DialogActions, TextField, Typography } from "@mui/material"; import { getMarkRange, getMarkType } from "@tiptap/core"; import { useEffect, useRef, useState } from "react"; import useKeyDown from "../hooks/useKeyDown"; import { formatHref as formatHrefDefault } from "../utils/links"; /** Shown when a user is adding/editing a Link for Tiptap. */ export default function EditLinkMenuContent({ editor, onCancel, onSave, labels, formatHref = formatHrefDefault, }) { var _a, _b, _c, _d, _e, _f; const existingHref = editor.isActive("link") ? editor.getAttributes("link").href : ""; const linkRange = getMarkRange(editor.state.selection.$from, getMarkType("link", editor.schema)); const linkText = linkRange ? editor.state.doc.textBetween(linkRange.from, linkRange.to) : ""; const selectedText = editor.state.doc.textBetween(editor.state.selection.$from.pos, editor.state.selection.$to.pos); // If we're on a link, we'll use the full link text, otherwise we'll fall back // to the selected text const initialText = linkText || selectedText; const [textValue, setTextValue] = useState(initialText); const [hrefValue, setHrefValue] = useState(existingHref); const textRef = useRef(null); const hrefRef = useRef(null); // If there's already a link where the user has clicked, they're "editing", // otherwise the menu has been brought up to add a new link const isNewLink = !existingHref; const addLinkTitle = (_a = labels === null || labels === void 0 ? void 0 : labels.editLinkAddTitle) !== null && _a !== void 0 ? _a : "Add link"; const editLinkTitle = (_b = labels === null || labels === void 0 ? void 0 : labels.editLinkEditTitle) !== null && _b !== void 0 ? _b : "Edit link"; const editMenuTitle = isNewLink ? addLinkTitle : editLinkTitle; // When bringing up the Popper of the `ControlledBubbleMenu` and using // autoFocus on the TextField elements, it is causing a scroll jump as // described here https://github.com/mui-org/material-ui/issues/16740. (It // seems the fix that was merged for that has since been undone, as the popper // styles now using `absolute` positioning again.) So we'll focus on the // appropriate input with `useEffect` below instead. useEffect(() => { var _a, _b; // We'll auto-focus on the text input if (a) it's not a new link, or (b) // it's a new link and they do not have some initial text already (e.g., // they brought up the link menu with some text selected already). Otherwise // well focus on the href input. const autoFocusOnTextInput = !isNewLink || !initialText; if (autoFocusOnTextInput) { (_a = textRef.current) === null || _a === void 0 ? void 0 : _a.focus({ preventScroll: true }); } else { (_b = hrefRef.current) === null || _b === void 0 ? void 0 : _b.focus({ preventScroll: true }); } }, [isNewLink, initialText]); // If the user presses escape, we should cancel useKeyDown("Escape", onCancel); function formatAndSetHref() { if (!hrefRef.current) { return; } setHrefValue(formatHref(hrefRef.current.value)); } const [isSubmitting, setIsSubmitting] = useState(false); return (_jsxs("form", { onSubmit: (event) => { var _a, _b, _c, _d; // Don't submit the form with a standard full-page request event.preventDefault(); // Don't let this event propagate upwards in the React tree, to prevent // submitting any form the rich text editor is wrapped in // (https://github.com/sjdemartini/mui-tiptap/issues/105) event.stopPropagation(); setIsSubmitting(true); const text = (_b = (_a = textRef.current) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : ""; const href = (_d = (_c = hrefRef.current) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : ""; onSave({ text: text, link: href }); setIsSubmitting(false); }, autoComplete: "off", children: [_jsx(Typography, { variant: "h6", children: editMenuTitle }), _jsx(TextField, { inputRef: textRef, value: textValue, disabled: isSubmitting, onChange: (event) => { setTextValue(event.target.value); }, label: (_c = labels === null || labels === void 0 ? void 0 : labels.editLinkTextInputLabel) !== null && _c !== void 0 ? _c : "Text", margin: "normal", size: "small", fullWidth: true, required: true }), _jsx(TextField, { inputRef: hrefRef, value: hrefValue, onChange: (event) => { setHrefValue(event.target.value); }, disabled: isSubmitting, label: (_d = labels === null || labels === void 0 ? void 0 : labels.editLinkHrefInputLabel) !== null && _d !== void 0 ? _d : "Link", margin: "dense", size: "small", type: "text" // "text" instead of "url" so that we can allow relative URLs , onBlur: formatAndSetHref, onKeyDown: (event) => { // If the user is trying to submit the form directly from the href field, make // sure we first format what they entered (which will update it to allow it to // pass URL field validation) if (event.key === "Enter") { formatAndSetHref(); } }, fullWidth: true, required: true }), _jsxs(DialogActions, { sx: { px: 0 }, children: [_jsx(Button, { onClick: onCancel, variant: "outlined", size: "small", children: (_e = labels === null || labels === void 0 ? void 0 : labels.editLinkCancelButtonLabel) !== null && _e !== void 0 ? _e : "Cancel" }), _jsx(Button, { type: "submit", color: "primary", variant: "outlined", size: "small", disabled: isSubmitting, children: (_f = labels === null || labels === void 0 ? void 0 : labels.editLinkSaveButtonLabel) !== null && _f !== void 0 ? _f : "Save" })] })] })); }