UNPKG

@atlaskit/editor-plugin-text-formatting

Version:

Text-formatting plugin for @atlaskit/editor-core

268 lines (267 loc) 9.46 kB
/** * @jsxRuntime classic * @jsx jsx */ import { useMemo } from 'react'; // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766 import { jsx } from '@emotion/react'; import { TOOLBAR_ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics'; import { getAriaKeyshortcuts, toggleBold, toggleCode, toggleItalic, toggleStrikethrough, toggleSubscript, toggleSuperscript, toggleUnderline, tooltip, ToolTipContent } from '@atlaskit/editor-common/keymaps'; import { toolbarMessages } from '@atlaskit/editor-common/messages'; import { editorCommandToPMCommand } from '@atlaskit/editor-common/preset'; import { shortcutStyle } from '@atlaskit/editor-shared-styles/shortcut'; import AngleBracketsIcon from '@atlaskit/icon/core/angle-brackets'; import BoldIcon from '@atlaskit/icon/core/text-bold'; import ItalicIcon from '@atlaskit/icon/core/text-italic'; import TextStrikethroughIcon from '@atlaskit/icon/core/text-strikethrough'; import UnderlineIcon from '@atlaskit/icon/core/text-underline'; import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments'; import { toggleCodeWithAnalytics, toggleEmWithAnalytics, toggleStrikeWithAnalytics, toggleStrongWithAnalytics, toggleSubscriptWithAnalytics, toggleSuperscriptWithAnalytics, toggleUnderlineWithAnalytics } from '../../../editor-commands/toggle-mark'; import { Subscript, Superscript } from '../icons'; import { getInputMethod } from '../input-method-utils'; import { IconTypes } from '../types'; const withInputMethod = (toolbarType, func) => editorCommandToPMCommand(func(getInputMethod(toolbarType))); const IconButtons = (editorAnalyticsAPI, toolbarType) => ({ strong: { buttonId: TOOLBAR_ACTION_SUBJECT_ID.TEXT_FORMATTING_STRONG, command: withInputMethod(toolbarType, toggleStrongWithAnalytics(editorAnalyticsAPI)), message: toolbarMessages.bold, tooltipKeymap: toggleBold, component: () => jsx(BoldIcon, { color: "currentColor", spacing: "spacious", label: "" }) }, em: { buttonId: TOOLBAR_ACTION_SUBJECT_ID.TEXT_FORMATTING_ITALIC, command: withInputMethod(toolbarType, toggleEmWithAnalytics(editorAnalyticsAPI)), message: toolbarMessages.italic, tooltipKeymap: toggleItalic, component: () => jsx(ItalicIcon, { color: "currentColor", spacing: "spacious", label: "" }) }, underline: { buttonId: TOOLBAR_ACTION_SUBJECT_ID.TEXT_FORMATTING_UNDERLINE, command: withInputMethod(toolbarType, toggleUnderlineWithAnalytics(editorAnalyticsAPI)), message: toolbarMessages.underline, tooltipKeymap: toggleUnderline, component: () => jsx(UnderlineIcon, { color: "currentColor", spacing: "spacious", label: "" }) }, strike: { command: withInputMethod(toolbarType, toggleStrikeWithAnalytics(editorAnalyticsAPI)), message: toolbarMessages.strike, tooltipKeymap: toggleStrikethrough }, code: { command: withInputMethod(toolbarType, toggleCodeWithAnalytics(editorAnalyticsAPI)), message: toolbarMessages.code, tooltipKeymap: toggleCode }, subscript: { command: withInputMethod(toolbarType, toggleSubscriptWithAnalytics(editorAnalyticsAPI)), message: toolbarMessages.subscript, tooltipKeymap: toggleSubscript }, superscript: { command: withInputMethod(toolbarType, toggleSuperscriptWithAnalytics(editorAnalyticsAPI)), message: toolbarMessages.superscript, tooltipKeymap: toggleSuperscript } }); const IconBefore = { strong: { icon: jsx(BoldIcon, { color: "currentColor", spacing: "spacious", label: "" }) }, em: { icon: jsx(ItalicIcon, { color: "currentColor", spacing: "spacious", label: "" }) }, underline: { icon: jsx(UnderlineIcon, { color: "currentColor", spacing: "spacious", label: "" }) }, strike: { icon: jsx(TextStrikethroughIcon, { label: "" }) }, code: { icon: jsx(AngleBracketsIcon, { color: "currentColor", spacing: "spacious", label: "" }) }, subscript: { icon: jsx(Subscript, null) }, superscript: { icon: jsx(Superscript, null) } }; const getIcon = ({ iconType, isDisabled, isActive, intl, editorAnalyticsAPI, toolbarType }) => { const icon = IconButtons(editorAnalyticsAPI, toolbarType)[iconType]; const iconBefore = IconBefore[iconType].icon; const content = intl.formatMessage(icon.message); const { tooltipKeymap } = icon; return { content, buttonId: icon.buttonId, iconMark: iconType, key: iconType, command: icon.command, iconElement: icon.component ? icon.component() : undefined, tooltipElement: tooltipKeymap ? jsx(ToolTipContent, { description: content, keymap: tooltipKeymap }) : undefined, elemBefore: editorExperiment('platform_editor_controls', 'variant1') ? iconBefore : undefined, elemAfter: tooltipKeymap ? // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage, @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 jsx("div", { css: shortcutStyle }, tooltip(tooltipKeymap)) : undefined, value: { name: iconType }, isActive, isDisabled, 'aria-label': tooltipKeymap ? tooltip(tooltipKeymap, String(content)) : String(content), 'aria-keyshortcuts': getAriaKeyshortcuts(tooltipKeymap) }; }; const IconsMarkSchema = { [IconTypes.strong]: 'strong', [IconTypes.em]: 'em', [IconTypes.strike]: 'strike', [IconTypes.code]: 'code', [IconTypes.underline]: 'underline', [IconTypes.superscript]: 'subsup', [IconTypes.subscript]: 'subsup' }; const buildMenuIconState = iconMark => ({ schema, textFormattingState }) => { const hasPluginState = Boolean(textFormattingState === null || textFormattingState === void 0 ? void 0 : textFormattingState.isInitialised); const markSchema = IconsMarkSchema[iconMark]; const hasSchemaMark = Boolean(schema.marks[markSchema]); if (!hasPluginState) { return { isActive: false, isDisabled: true, isHidden: false, hasSchemaMark }; } const isActive = textFormattingState === null || textFormattingState === void 0 ? void 0 : textFormattingState[`${iconMark}Active`]; const isDisabled = textFormattingState === null || textFormattingState === void 0 ? void 0 : textFormattingState[`${iconMark}Disabled`]; const isHidden = textFormattingState === null || textFormattingState === void 0 ? void 0 : textFormattingState[`${iconMark}Hidden`]; return { isActive: Boolean(isActive), isDisabled: Boolean(isDisabled), isHidden: Boolean(isHidden), hasSchemaMark }; }; const buildIcon = (iconMark, editorAnalyticsAPI, toolbarType) => { const getState = buildMenuIconState(iconMark); return ({ schema, textFormattingState, intl, isToolbarDisabled }) => { const iconState = getState({ schema, textFormattingState }); const { isActive, isDisabled, isHidden, hasSchemaMark } = iconState; const iconComponent = useMemo(() => getIcon({ iconType: IconTypes[iconMark], isDisabled: isToolbarDisabled || isDisabled, isActive, intl, editorAnalyticsAPI, toolbarType }), [isToolbarDisabled, isDisabled, isActive, intl]); const shouldRenderIcon = hasSchemaMark && !isHidden; return useMemo(() => shouldRenderIcon ? iconComponent : null, [shouldRenderIcon, iconComponent]); }; }; export const useFormattingIcons = ({ isToolbarDisabled, textFormattingState, schema, intl, editorAnalyticsAPI, toolbarType }) => { const props = { schema, textFormattingState, intl, isToolbarDisabled: Boolean(isToolbarDisabled), toolbarType }; const buildStrongIcon = buildIcon(IconTypes.strong, editorAnalyticsAPI, toolbarType); const buildEmIcon = buildIcon(IconTypes.em, editorAnalyticsAPI, toolbarType); const buildUnderlineIcon = buildIcon(IconTypes.underline, editorAnalyticsAPI, toolbarType); const buildStrikeIcon = buildIcon(IconTypes.strike, editorAnalyticsAPI, toolbarType); const buildCodeIcon = buildIcon(IconTypes.code, editorAnalyticsAPI, toolbarType); const buildSubscriptIcon = buildIcon(IconTypes.subscript, editorAnalyticsAPI, toolbarType); const buildSuperscriptIcon = buildIcon(IconTypes.superscript, editorAnalyticsAPI, toolbarType); const strongIcon = buildStrongIcon(props); const emIcon = buildEmIcon(props); const underlineIcon = buildUnderlineIcon(props); const strikeIcon = buildStrikeIcon(props); const codeIcon = buildCodeIcon(props); const subscriptIcon = buildSubscriptIcon(props); const superscriptIcon = buildSuperscriptIcon(props); const result = useMemo(() => [strongIcon, emIcon, underlineIcon, strikeIcon, codeIcon, subscriptIcon, superscriptIcon], [strongIcon, emIcon, underlineIcon, strikeIcon, codeIcon, subscriptIcon, superscriptIcon]); return result; }; export const useHasFormattingActived = ({ iconTypeList, textFormattingState }) => { const hasActiveFormatting = useMemo(() => { if (!(textFormattingState !== null && textFormattingState !== void 0 && textFormattingState.isInitialised)) { return false; } return iconTypeList.some(iconType => textFormattingState[`${iconType}Active`]); }, [textFormattingState, iconTypeList]); return hasActiveFormatting; };