mui-tiptap
Version:
A Material-UI (MUI) styled WYSIWYG rich text editor, using Tiptap
131 lines (130 loc) • 8 kB
JavaScript
;
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 = MenuSelectFontFamily;
const jsx_runtime_1 = require("react/jsx-runtime");
/// <reference types="@tiptap/extension-font-family" />
const MenuItem_1 = __importDefault(require("@mui/material/MenuItem"));
const styles_1 = require("@mui/material/styles");
const clsx_1 = require("clsx");
const context_1 = require("../context");
const styles_2 = require("../styles");
const getAttributesForEachSelected_1 = require("../utils/getAttributesForEachSelected");
const MenuSelect_1 = __importDefault(require("./MenuSelect"));
const MenuSelectFontFamily_classes_1 = require("./MenuSelectFontFamily.classes");
const componentName = (0, styles_2.getUtilityComponentName)("MenuSelectFontFamily");
const MenuSelectFontFamilyRoot = (0, styles_1.styled)((MenuSelect_1.default), {
name: componentName,
slot: "root",
overridesResolver: (props, styles) => styles.root,
})({
[`& .${MenuSelectFontFamily_classes_1.menuSelectFontFamilyClasses.selectInput}`]: {
// We use a fixed width so that the Select element won't change sizes as
// the selected option changes
width: 55,
},
});
// Use this as a sentinel value so we can handle the case that the user's
// selection includes multiple different font families. There won't be a visible
// "option" in the Select for this value, and this will allow the user to set
// the current font family to "Default" or to any of the multiple values, and
// have it take effect. See more comments around `currentFontFamily` below.
const MULTIPLE_FAMILIES_SELECTED_VALUE = "MULTIPLE";
/** A font-family selector for use with the Tiptap FontFamily extension. */
function MenuSelectFontFamily(inProps) {
var _a;
const props = (0, styles_1.useThemeProps)({ props: inProps, name: componentName });
const { options, hideUnsetOption = false, unsetOptionLabel = "Default", emptyLabel = "Font", classes = {}, sx } = props, menuSelectProps = __rest(props, ["options", "hideUnsetOption", "unsetOptionLabel", "emptyLabel", "classes", "sx"]);
const editor = (0, context_1.useRichTextEditorContext)();
// Determine if all of the selected content shares the same set font family.
// Scenarios:
// 1) If there is exactly one font family amongst the selected content and all
// of the selected content has the font family set, we'll show that as the
// current Selected value (as a user would expect).
// 2) If there are multiple families used in the selected content or some
// selected content has font family set and other content does not, we'll
// assign the Select's `value` to a sentinel variable so that users can
// unset the families or can change to any given family.
// 3) Otherwise (no font family is set in any selected content), we'll show the
// unsetOption as selected.
const allCurrentTextStyleAttrs = editor
? (0, getAttributesForEachSelected_1.getAttributesForEachSelected)(editor.state, "textStyle")
: [];
const isTextStyleAppliedToEntireSelection = !!(editor === null || editor === void 0 ? void 0 : editor.isActive("textStyle"));
const currentFontFamilies = allCurrentTextStyleAttrs.map((attrs) => { var _a; return (_a = attrs.fontFamily) !== null && _a !== void 0 ? _a : ""; });
if (!isTextStyleAppliedToEntireSelection) {
// If there is some selected content that does not have textStyle, we can
// treat it the same as a selected textStyle mark with fontFamily set to
// null or ""
currentFontFamilies.push("");
}
const numUniqueCurrentFontFamilies = new Set(currentFontFamilies).size;
let currentFontFamily;
if (numUniqueCurrentFontFamilies === 1) {
// There's exactly one font family selected, so show that
currentFontFamily = currentFontFamilies[0];
}
else if (numUniqueCurrentFontFamilies > 1) {
// There are multiple font families (either explicitly, or because some of the
// selection has a font family set and some does not). This is similar to what
// Microsoft Word and Google Docs do, for instance, showing the font family
// input as blank when there are multiple values. If we simply set
// currentFontFamily as "" here, then the "unset option" would show as
// selected, which would prevent the user from unsetting the font families
// for the selected content (since Select onChange does not fire when the
// currently selected option is chosen again).
currentFontFamily = MULTIPLE_FAMILIES_SELECTED_VALUE;
}
else {
// Show as unset (empty), since there are no font families in any of the
// selected content. This will show the "unset option" with the
// unsetOptionLabel as selected, if `hideUnsetOption` is false.
currentFontFamily = "";
}
return ((0, jsx_runtime_1.jsxs)(MenuSelectFontFamilyRoot, Object.assign({ onChange: (event) => {
const value = event.target.value;
if (value) {
editor === null || editor === void 0 ? void 0 : editor.chain().setFontFamily(value).focus().run();
}
else {
editor === null || editor === void 0 ? void 0 : editor.chain().unsetFontFamily().focus().run();
}
}, disabled:
// Pass an arbitrary value just to check `can()`
!(editor === null || editor === void 0 ? void 0 : editor.isEditable) || !editor.can().setFontFamily("serif"), renderValue: (value) => {
var _a, _b;
if (!value || value === MULTIPLE_FAMILIES_SELECTED_VALUE) {
return emptyLabel;
}
return (_b = (_a = options.find((option) => option.value === value)) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : value;
}, displayEmpty: true, tooltipTitle: "Font" }, menuSelectProps, {
// We don't want to pass any non-string falsy values here, always falling
// back to ""
value: currentFontFamily || "", inputProps: Object.assign(Object.assign({}, menuSelectProps.inputProps), { className: (0, clsx_1.clsx)([
MenuSelectFontFamily_classes_1.menuSelectFontFamilyClasses.selectInput,
classes.selectInput,
(_a = menuSelectProps.inputProps) === null || _a === void 0 ? void 0 : _a.className,
]) }), className: (0, clsx_1.clsx)([
MenuSelectFontFamily_classes_1.menuSelectFontFamilyClasses.root,
classes.root,
menuSelectProps.className,
]), sx: sx, children: [!hideUnsetOption && (
// Allow users to unset the font-family
(0, jsx_runtime_1.jsx)(MenuItem_1.default, { value: "", children: unsetOptionLabel })), (0, jsx_runtime_1.jsx)(MenuItem_1.default, { style: { display: "none" }, value: MULTIPLE_FAMILIES_SELECTED_VALUE }), options.map((fontFamilyOption) => {
var _a;
return ((0, jsx_runtime_1.jsx)(MenuItem_1.default, { value: fontFamilyOption.value, children: (0, jsx_runtime_1.jsx)("span", { style: { fontFamily: fontFamilyOption.value }, children: (_a = fontFamilyOption.label) !== null && _a !== void 0 ? _a : fontFamilyOption.value }) }, fontFamilyOption.value));
})] })));
}