UNPKG

mui-tiptap

Version:

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

301 lines (300 loc) 21.6 kB
"use strict"; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = MenuSelectHeading; const jsx_runtime_1 = require("react/jsx-runtime"); /// <reference types="@tiptap/extension-paragraph" /> const MenuItem_1 = __importDefault(require("@mui/material/MenuItem")); const styles_1 = require("@mui/material/styles"); const clsx_1 = require("clsx"); const react_1 = require("react"); const context_1 = require("../context"); const styles_2 = require("../styles"); const getAttributesForEachSelected_1 = require("../utils/getAttributesForEachSelected"); const platform_1 = require("../utils/platform"); const MenuButtonTooltip_1 = __importDefault(require("./MenuButtonTooltip")); const MenuSelect_1 = __importDefault(require("./MenuSelect")); const MenuSelectHeading_classes_1 = require("./MenuSelectHeading.classes"); const componentName = (0, styles_2.getUtilityComponentName)("MenuSelectHeading"); const MenuSelectHeadingRoot = (0, styles_1.styled)((MenuSelect_1.default), { name: componentName, slot: "root", overridesResolver: (props, styles) => styles.root, })({ [`& .${MenuSelectHeading_classes_1.menuSelectHeadingClasses.selectInput}`]: { // We use a fixed width so that the Select element won't change sizes as // the selected option changes (which would shift other elements in the // menu bar) width: 77, }, }); const MenuSelectMenuOption = (0, styles_1.styled)(MenuButtonTooltip_1.default, { name: componentName, slot: "menuOption", overridesResolver: (props, styles) => styles.menuOption, })({ // These styles ensure the item fills its MenuItem container, and the // tooltip appears in the same place when hovering over the item generally // (not just the text of the item) display: "block", width: "100%", }); const MenuSelectHeadingOption = (0, styles_1.styled)(MenuSelectMenuOption, { name: componentName, slot: "headingOption", overridesResolver: (props, styles) => styles.option, })({ marginBlockStart: 0, marginBlockEnd: 0, fontWeight: "bold", }); const MenuSelectHeadingOption1 = (0, styles_1.styled)(MenuSelectHeadingOption, { name: componentName, slot: "headingOption1", overridesResolver: (props, styles) => styles.headingOption1, })(({ theme }) => ({ fontSize: (0, styles_2.getEditorStyles)(theme)["& h1"].fontSize, })); const MenuSelectHeadingOption2 = (0, styles_1.styled)(MenuSelectHeadingOption, { name: componentName, slot: "headingOption2", overridesResolver: (props, styles) => styles.headingOption2, })(({ theme }) => ({ fontSize: (0, styles_2.getEditorStyles)(theme)["& h2"].fontSize, })); const MenuSelectHeadingOption3 = (0, styles_1.styled)(MenuSelectHeadingOption, { name: componentName, slot: "headingOption3", overridesResolver: (props, styles) => styles.headingOption3, })(({ theme }) => ({ fontSize: (0, styles_2.getEditorStyles)(theme)["& h3"].fontSize, })); const MenuSelectHeadingOption4 = (0, styles_1.styled)(MenuSelectHeadingOption, { name: componentName, slot: "headingOption4", overridesResolver: (props, styles) => styles.headingOption4, })(({ theme }) => ({ fontSize: (0, styles_2.getEditorStyles)(theme)["& h4"].fontSize, })); const MenuSelectHeadingOption5 = (0, styles_1.styled)(MenuSelectHeadingOption, { name: componentName, slot: "headingOption5", overridesResolver: (props, styles) => styles.headingOption5, })(({ theme }) => ({ fontSize: (0, styles_2.getEditorStyles)(theme)["& h5"].fontSize, })); const MenuSelectHeadingOption6 = (0, styles_1.styled)(MenuSelectHeadingOption, { name: componentName, slot: "headingOption6", overridesResolver: (props, styles) => styles.headingOption6, })(({ theme }) => ({ fontSize: (0, styles_2.getEditorStyles)(theme)["& h6"].fontSize, })); const HEADING_OPTION_VALUES = { Paragraph: "Paragraph", Heading1: "Heading 1", Heading2: "Heading 2", Heading3: "Heading 3", Heading4: "Heading 4", Heading5: "Heading 5", Heading6: "Heading 6", }; const HEADING_OPTION_VALUE_TO_LEVEL = { [HEADING_OPTION_VALUES.Heading1]: 1, [HEADING_OPTION_VALUES.Heading2]: 2, [HEADING_OPTION_VALUES.Heading3]: 3, [HEADING_OPTION_VALUES.Heading4]: 4, [HEADING_OPTION_VALUES.Heading5]: 5, [HEADING_OPTION_VALUES.Heading6]: 6, }; const LEVEL_TO_HEADING_OPTION_VALUE = { 1: HEADING_OPTION_VALUES.Heading1, 2: HEADING_OPTION_VALUES.Heading2, 3: HEADING_OPTION_VALUES.Heading3, 4: HEADING_OPTION_VALUES.Heading4, 5: HEADING_OPTION_VALUES.Heading5, 6: HEADING_OPTION_VALUES.Heading6, }; function MenuSelectHeading(inProps) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q; const props = (0, styles_1.useThemeProps)({ props: inProps, name: componentName }); const { labels, shortcutKeys: shortcutKeyOverrides, hideShortcuts = false, classes = {}, sx } = props, menuSelectProps = __rest(props, ["labels", "shortcutKeys", "hideShortcuts", "classes", "sx"]); const shortcutKeys = hideShortcuts ? undefined : { paragraph: (_a = shortcutKeyOverrides === null || shortcutKeyOverrides === void 0 ? void 0 : shortcutKeyOverrides.paragraph) !== null && _a !== void 0 ? _a : ["mod", "alt", "0"], heading1: (_b = shortcutKeyOverrides === null || shortcutKeyOverrides === void 0 ? void 0 : shortcutKeyOverrides.heading1) !== null && _b !== void 0 ? _b : ["mod", "alt", "1"], heading2: (_c = shortcutKeyOverrides === null || shortcutKeyOverrides === void 0 ? void 0 : shortcutKeyOverrides.heading2) !== null && _c !== void 0 ? _c : ["mod", "alt", "2"], heading3: (_d = shortcutKeyOverrides === null || shortcutKeyOverrides === void 0 ? void 0 : shortcutKeyOverrides.heading3) !== null && _d !== void 0 ? _d : ["mod", "alt", "3"], heading4: (_e = shortcutKeyOverrides === null || shortcutKeyOverrides === void 0 ? void 0 : shortcutKeyOverrides.heading4) !== null && _e !== void 0 ? _e : ["mod", "alt", "4"], heading5: (_f = shortcutKeyOverrides === null || shortcutKeyOverrides === void 0 ? void 0 : shortcutKeyOverrides.heading5) !== null && _f !== void 0 ? _f : ["mod", "alt", "5"], heading6: (_g = shortcutKeyOverrides === null || shortcutKeyOverrides === void 0 ? void 0 : shortcutKeyOverrides.heading6) !== null && _g !== void 0 ? _g : ["mod", "alt", "6"], }; const editor = (0, context_1.useRichTextEditorContext)(); const handleHeadingType = (0, react_1.useCallback)((event) => { const value = event.target.value; if (value === HEADING_OPTION_VALUES.Paragraph) { editor === null || editor === void 0 ? void 0 : editor.chain().setParagraph().focus().run(); } else if (value in HEADING_OPTION_VALUE_TO_LEVEL) { editor === null || editor === void 0 ? void 0 : editor.chain().setHeading({ level: HEADING_OPTION_VALUE_TO_LEVEL[value], }).focus().run(); } }, [editor]); let selectedValue = ""; let currentLevel; if (editor === null || editor === void 0 ? void 0 : editor.isActive("paragraph")) { selectedValue = HEADING_OPTION_VALUES.Paragraph; } else if (editor === null || editor === void 0 ? void 0 : editor.isActive("heading")) { const currentNodeHeadingAttributes = (0, getAttributesForEachSelected_1.getAttributesForEachSelected)(editor.state, "heading"); const currentNodeLevels = currentNodeHeadingAttributes.map((attrs) => attrs.level); const numCurrentNodeLevels = new Set(currentNodeLevels).size; // We only want to show a selected level value if all of the selected nodes // have the same level. (That way a user can properly change the level when // selecting across two separate headings, and so we don't mistakenly just // show the first of the selected nodes' levels and not allow changing all // selected to that heading level. See // https://github.com/ueberdosis/tiptap/issues/3481.) currentLevel = numCurrentNodeLevels === 1 ? currentNodeLevels[0] : undefined; if (currentLevel && currentLevel in LEVEL_TO_HEADING_OPTION_VALUE) { selectedValue = LEVEL_TO_HEADING_OPTION_VALUE[currentLevel]; } } const isCurrentlyParagraphOrHeading = selectedValue !== ""; const canSetParagraph = !!(editor === null || editor === void 0 ? void 0 : editor.can().setParagraph()); // Figure out which settings the user has enabled with the heading extension const enabledHeadingLevels = (0, react_1.useMemo)(() => { var _a; const headingExtension = editor === null || editor === void 0 ? void 0 : editor.extensionManager.extensions.find((extension) => extension.name == "heading"); return new Set((_a = headingExtension === null || headingExtension === void 0 ? void 0 : headingExtension.options.levels) !== null && _a !== void 0 ? _a : []); }, [editor]); // In determining whether we can set a heading, at least one heading level // must be enabled in the extension configuration. We have to pass a level // when running `can().setHeading()`, so we just use the first one that is // enabled. And since some Tiptap versions return `false` for // `can().setHeading()` when passing the current level, we also have to check // whether that arbitrary first level is the `currentLevel` (see // https://github.com/sjdemartini/mui-tiptap/issues/197). const firstEnabledHeadingResult = enabledHeadingLevels.values().next(); const firstEnabledHeading = firstEnabledHeadingResult.done ? undefined : firstEnabledHeadingResult.value; const canSetHeading = firstEnabledHeading !== undefined && (currentLevel === firstEnabledHeading || !!(editor === null || editor === void 0 ? void 0 : editor.can().setHeading({ level: firstEnabledHeading }))); return ( // We currently have to specify that the value is of type // `HeadingOptionValue | ""` rather than just `HeadingOptionValue` due to // the bug reported here https://github.com/mui/material-ui/issues/34083. We // need it to support "" as a possible value in the `renderValue` function // below since we have `displayEmpty=true`, and the types don't properly // handle that scenario. (0, jsx_runtime_1.jsxs)(MenuSelectHeadingRoot, Object.assign({ onChange: handleHeadingType, disabled: !(editor === null || editor === void 0 ? void 0 : editor.isEditable) || (!isCurrentlyParagraphOrHeading && !canSetParagraph && !canSetHeading), displayEmpty: true, renderValue: (selected) => { var _a, _b; let result; if (selected === "") { // Handle the deprecated `emptyValue` label name, falling back to the // newer `labels.empty`, and finally our default empty label // eslint-disable-next-line @typescript-eslint/no-deprecated result = (_b = (_a = labels === null || labels === void 0 ? void 0 : labels.emptyValue) !== null && _a !== void 0 ? _a : labels === null || labels === void 0 ? void 0 : labels.empty) !== null && _b !== void 0 ? _b : (0, jsx_runtime_1.jsx)("em", { children: "Change to\u2026" }); } else if (selected === HEADING_OPTION_VALUES.Paragraph) { result = labels === null || labels === void 0 ? void 0 : labels.paragraph; } else if (selected === HEADING_OPTION_VALUES.Heading1) { result = labels === null || labels === void 0 ? void 0 : labels.heading1; } else if (selected === HEADING_OPTION_VALUES.Heading2) { result = labels === null || labels === void 0 ? void 0 : labels.heading2; } else if (selected === HEADING_OPTION_VALUES.Heading3) { result = labels === null || labels === void 0 ? void 0 : labels.heading3; } else if (selected === HEADING_OPTION_VALUES.Heading4) { result = labels === null || labels === void 0 ? void 0 : labels.heading4; } else if (selected === HEADING_OPTION_VALUES.Heading5) { result = labels === null || labels === void 0 ? void 0 : labels.heading5; // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition } else if (selected === HEADING_OPTION_VALUES.Heading6) { result = labels === null || labels === void 0 ? void 0 : labels.heading6; } return result !== null && result !== void 0 ? result : selected; }, tooltipTitle: "Styles" }, menuSelectProps, { value: selectedValue, inputProps: Object.assign(Object.assign({}, menuSelectProps.inputProps), { className: (0, clsx_1.clsx)([ MenuSelectHeading_classes_1.menuSelectHeadingClasses.selectInput, classes.selectInput, (_h = menuSelectProps.inputProps) === null || _h === void 0 ? void 0 : _h.className, ]) }), className: (0, clsx_1.clsx)([ MenuSelectHeading_classes_1.menuSelectHeadingClasses.root, classes.root, menuSelectProps.className, ]), sx: sx, children: [(0, jsx_runtime_1.jsx)(MenuItem_1.default, { value: HEADING_OPTION_VALUES.Paragraph, disabled: !isCurrentlyParagraphOrHeading && !canSetParagraph, "aria-description": (0, platform_1.getShortcutKeysDescription)(shortcutKeys === null || shortcutKeys === void 0 ? void 0 : shortcutKeys.paragraph), children: (0, jsx_runtime_1.jsx)(MenuSelectMenuOption, { label: "", shortcutKeys: shortcutKeys === null || shortcutKeys === void 0 ? void 0 : shortcutKeys.paragraph, placement: "right", classes: { contentWrapper: (0, clsx_1.clsx)([ MenuSelectHeading_classes_1.menuSelectHeadingClasses.menuOption, classes.menuOption, MenuSelectHeading_classes_1.menuSelectHeadingClasses.paragraphOption, classes.paragraphOption, ]), }, children: (_j = labels === null || labels === void 0 ? void 0 : labels.paragraph) !== null && _j !== void 0 ? _j : HEADING_OPTION_VALUES.Paragraph }) }), enabledHeadingLevels.has(1) && ((0, jsx_runtime_1.jsx)(MenuItem_1.default, { value: HEADING_OPTION_VALUES.Heading1, disabled: !canSetHeading, "aria-description": (0, platform_1.getShortcutKeysDescription)(shortcutKeys === null || shortcutKeys === void 0 ? void 0 : shortcutKeys.heading1), children: (0, jsx_runtime_1.jsx)(MenuSelectHeadingOption1, { label: "", shortcutKeys: shortcutKeys === null || shortcutKeys === void 0 ? void 0 : shortcutKeys.heading1, placement: "right", className: (0, clsx_1.clsx)([ MenuSelectHeading_classes_1.menuSelectHeadingClasses.menuOption, classes.menuOption, MenuSelectHeading_classes_1.menuSelectHeadingClasses.headingOption, classes.headingOption, MenuSelectHeading_classes_1.menuSelectHeadingClasses.headingOption1, classes.headingOption1, ]), children: (_k = labels === null || labels === void 0 ? void 0 : labels.heading1) !== null && _k !== void 0 ? _k : HEADING_OPTION_VALUES.Heading1 }) })), enabledHeadingLevels.has(2) && ((0, jsx_runtime_1.jsx)(MenuItem_1.default, { value: HEADING_OPTION_VALUES.Heading2, disabled: !canSetHeading, "aria-description": (0, platform_1.getShortcutKeysDescription)(shortcutKeys === null || shortcutKeys === void 0 ? void 0 : shortcutKeys.heading2), children: (0, jsx_runtime_1.jsx)(MenuSelectHeadingOption2, { label: "", shortcutKeys: shortcutKeys === null || shortcutKeys === void 0 ? void 0 : shortcutKeys.heading2, placement: "right", className: (0, clsx_1.clsx)([ MenuSelectHeading_classes_1.menuSelectHeadingClasses.menuOption, classes.menuOption, MenuSelectHeading_classes_1.menuSelectHeadingClasses.headingOption, classes.headingOption, MenuSelectHeading_classes_1.menuSelectHeadingClasses.headingOption2, classes.headingOption2, ]), children: (_l = labels === null || labels === void 0 ? void 0 : labels.heading2) !== null && _l !== void 0 ? _l : HEADING_OPTION_VALUES.Heading2 }) })), enabledHeadingLevels.has(3) && ((0, jsx_runtime_1.jsx)(MenuItem_1.default, { value: HEADING_OPTION_VALUES.Heading3, disabled: !canSetHeading, "aria-description": (0, platform_1.getShortcutKeysDescription)(shortcutKeys === null || shortcutKeys === void 0 ? void 0 : shortcutKeys.heading3), children: (0, jsx_runtime_1.jsx)(MenuSelectHeadingOption3, { label: "", shortcutKeys: shortcutKeys === null || shortcutKeys === void 0 ? void 0 : shortcutKeys.heading3, placement: "right", className: (0, clsx_1.clsx)([ MenuSelectHeading_classes_1.menuSelectHeadingClasses.menuOption, classes.menuOption, MenuSelectHeading_classes_1.menuSelectHeadingClasses.headingOption, classes.headingOption, MenuSelectHeading_classes_1.menuSelectHeadingClasses.headingOption3, classes.headingOption3, ]), children: (_m = labels === null || labels === void 0 ? void 0 : labels.heading3) !== null && _m !== void 0 ? _m : HEADING_OPTION_VALUES.Heading3 }) })), enabledHeadingLevels.has(4) && ((0, jsx_runtime_1.jsx)(MenuItem_1.default, { value: HEADING_OPTION_VALUES.Heading4, disabled: !canSetHeading, "aria-description": (0, platform_1.getShortcutKeysDescription)(shortcutKeys === null || shortcutKeys === void 0 ? void 0 : shortcutKeys.heading4), children: (0, jsx_runtime_1.jsx)(MenuSelectHeadingOption4, { label: "", shortcutKeys: shortcutKeys === null || shortcutKeys === void 0 ? void 0 : shortcutKeys.heading4, placement: "right", className: (0, clsx_1.clsx)([ MenuSelectHeading_classes_1.menuSelectHeadingClasses.menuOption, classes.menuOption, MenuSelectHeading_classes_1.menuSelectHeadingClasses.headingOption, classes.headingOption, MenuSelectHeading_classes_1.menuSelectHeadingClasses.headingOption4, classes.headingOption4, ]), children: (_o = labels === null || labels === void 0 ? void 0 : labels.heading4) !== null && _o !== void 0 ? _o : HEADING_OPTION_VALUES.Heading4 }) })), enabledHeadingLevels.has(5) && ((0, jsx_runtime_1.jsx)(MenuItem_1.default, { value: HEADING_OPTION_VALUES.Heading5, disabled: !canSetHeading, "aria-description": (0, platform_1.getShortcutKeysDescription)(shortcutKeys === null || shortcutKeys === void 0 ? void 0 : shortcutKeys.heading5), children: (0, jsx_runtime_1.jsx)(MenuSelectHeadingOption5, { label: "", shortcutKeys: shortcutKeys === null || shortcutKeys === void 0 ? void 0 : shortcutKeys.heading5, placement: "right", className: (0, clsx_1.clsx)([ MenuSelectHeading_classes_1.menuSelectHeadingClasses.menuOption, classes.menuOption, MenuSelectHeading_classes_1.menuSelectHeadingClasses.headingOption, classes.headingOption, MenuSelectHeading_classes_1.menuSelectHeadingClasses.headingOption5, classes.headingOption5, ]), children: (_p = labels === null || labels === void 0 ? void 0 : labels.heading5) !== null && _p !== void 0 ? _p : HEADING_OPTION_VALUES.Heading5 }) })), enabledHeadingLevels.has(6) && ((0, jsx_runtime_1.jsx)(MenuItem_1.default, { value: HEADING_OPTION_VALUES.Heading6, disabled: !canSetHeading, "aria-description": (0, platform_1.getShortcutKeysDescription)(shortcutKeys === null || shortcutKeys === void 0 ? void 0 : shortcutKeys.heading6), children: (0, jsx_runtime_1.jsx)(MenuSelectHeadingOption6, { label: "", shortcutKeys: shortcutKeys === null || shortcutKeys === void 0 ? void 0 : shortcutKeys.heading6, placement: "right", className: (0, clsx_1.clsx)([ MenuSelectHeading_classes_1.menuSelectHeadingClasses.menuOption, classes.menuOption, MenuSelectHeading_classes_1.menuSelectHeadingClasses.headingOption, classes.headingOption, MenuSelectHeading_classes_1.menuSelectHeadingClasses.headingOption6, classes.headingOption6, ]), children: (_q = labels === null || labels === void 0 ? void 0 : labels.heading6) !== null && _q !== void 0 ? _q : HEADING_OPTION_VALUES.Heading6 }) }))] }))); }