UNPKG

@atlaskit/editor-plugin-floating-toolbar

Version:

Floating toolbar plugin for @atlaskit/editor-core

733 lines (723 loc) 32.5 kB
import _extends from "@babel/runtime/helpers/extends"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; /* eslint-disable @atlaskit/design-system/no-css-tagged-template-expression -- needs manual remediation */ /** * @jsxRuntime classic * @jsx jsx */ import React, { Component } from 'react'; // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766 import { css, jsx } from '@emotion/react'; import { injectIntl } from 'react-intl'; import ButtonGroup from '@atlaskit/button/button-group'; import { areSameItems, messages } from '@atlaskit/editor-common/floating-toolbar'; import commonMessages from '@atlaskit/editor-common/messages'; import { areToolbarFlagsEnabled } from '@atlaskit/editor-common/toolbar-flag-check'; import { Announcer, FloatingToolbarButton as Button, FloatingToolbarSeparator as Separator } from '@atlaskit/editor-common/ui'; import { backgroundPaletteTooltipMessages } from '@atlaskit/editor-common/ui-color'; import { ColorPickerButton, ToolbarArrowKeyNavigationProvider } from '@atlaskit/editor-common/ui-menu'; import { hexToEditorBackgroundPaletteColor } from '@atlaskit/editor-palette'; import ShowMoreHorizontalIcon from '@atlaskit/icon/core/show-more-horizontal'; import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals'; import { checkShouldForceFocusAndApply, forceFocusSelector } from '../pm-plugins/force-focus'; import { showConfirmDialog } from '../pm-plugins/toolbar-data/commands'; import Dropdown from './Dropdown'; import { EmojiPickerButton } from './EmojiPickerButton'; import { ExtensionsPlaceholder } from './ExtensionsPlaceholder'; import { Input } from './Input'; import { ScrollButton } from './ScrollButton'; import { ScrollButtons } from './ScrollButtons'; import Select from './Select'; // eslint-disable-next-line jsdoc/require-jsdoc export function groupItems(items, areAnyNewToolbarFlagsEnabled) { const groupItems = items.reduce((accumulator, item, i) => { const { finalOutput, buttonGroup } = accumulator; if (item.type === 'button') { const notLastItem = i < items.length - 1; const nextItemIsButton = items[i + 1] && items[i + 1].type === 'button'; const wasPreviousButton = items[i - 1] && items[i - 1].type === 'button'; const shouldBeRadioButton = notLastItem && nextItemIsButton || wasPreviousButton; // Only group as radio button if not explicitly set to false const isRadioButton = !expValEquals('platform_editor_august_a11y', 'isEnabled', true) ? shouldBeRadioButton : shouldBeRadioButton && item.isRadioButton !== false; if (isRadioButton) { item.isRadioButton = true; buttonGroup.push(item); if (!nextItemIsButton && wasPreviousButton) { finalOutput.push(buttonGroup); accumulator.buttonGroup = []; } } else { finalOutput.push(item); } } else if (item.type === 'separator' && areAnyNewToolbarFlagsEnabled) { var _items; const isLeadingSeparator = i === 0; const isTrailingSeparator = i === items.length - 1; const isDuplicateSeparator = ((_items = items[i - 1]) === null || _items === void 0 ? void 0 : _items.type) === 'separator'; !isLeadingSeparator && !isTrailingSeparator && !isDuplicateSeparator && finalOutput.push(item); } else { finalOutput.push(item); } return accumulator; }, { buttonGroup: [], finalOutput: [] }); return groupItems.finalOutput; } const ToolbarItems = /*#__PURE__*/React.memo(({ items, groupLabel, dispatchCommand, popupsMountPoint, popupsBoundariesElement, editorView, dispatchAnalyticsEvent, popupsScrollableElement, scrollable, providerFactory, extensionsProvider, node, setDisableScroll, mountRef, api, intl }) => { const emojiAndColourPickerMountPoint = scrollable ? popupsMountPoint || (editorView === null || editorView === void 0 ? void 0 : editorView.dom.closest('.fabric-editor-popup-scroll-parent')) || (editorView === null || editorView === void 0 ? void 0 : editorView.dom.closest('.ak-editor-content-area')) || undefined : popupsMountPoint; const areAnyNewToolbarFlagsEnabled = areToolbarFlagsEnabled(Boolean(api === null || api === void 0 ? void 0 : api.toolbar)); const renderItem = (item, idx) => { var _api$contextPanel, _api$extension; switch (item.type) { case 'button': // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-explicit-any const ButtonIcon = item.icon; const onClickHandler = () => { if (item.confirmDialog) { dispatchCommand(showConfirmDialog(idx)); } else { dispatchCommand(item.onClick); if (item.focusEditoronEnter && !(editorView !== null && editorView !== void 0 && editorView.hasFocus())) { editorView === null || editorView === void 0 ? void 0 : editorView.focus(); } } }; const getIconColor = (disabled, selected) => { if (disabled) { return "var(--ds-icon-disabled, #080F214A)"; } if (selected) { return "var(--ds-icon-selected, #1868DB)"; } return 'currentColor'; }; return jsx(Button // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop, @atlaskit/design-system/no-unsafe-style-overrides -- Ignored via go/DSP-18766 , { className: item.className, key: idx, title: item.title, href: item.href, icon: item.icon ? jsx(ButtonIcon, { color: getIconColor(item.disabled, item.selected), spacing: "spacious", label: undefined, "aria-hidden": true // Icon is described by the button for screen readers }) : undefined, iconAfter: item.iconAfter ? jsx(item.iconAfter, { label: "" }) : undefined, appearance: item.appearance, target: item.target, onClick: onClickHandler // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onMouseEnter: () => dispatchCommand(item.onMouseEnter) // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onMouseLeave: () => dispatchCommand(item.onMouseLeave) // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onFocus: () => dispatchCommand(item.onFocus) // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onBlur: () => dispatchCommand(item.onBlur), onMount: item.onMount, onUnmount: item.onUnmount, selected: item.selected, disabled: item.disabled, tooltipContent: item.tooltipContent, testId: item.testId, hideTooltipOnClick: item.hideTooltipOnClick, ariaHasPopup: item.ariaHasPopup, tabIndex: item.tabIndex, isRadioButton: item.isRadioButton, ariaLabel: expValEquals('platform_editor_floating_toolbar_button_aria_label', 'isEnabled', true) ? item === null || item === void 0 ? void 0 : item.ariaLabel : undefined, pulse: item.pulse, interactionName: item.interactionName, areAnyNewToolbarFlagsEnabled: areAnyNewToolbarFlagsEnabled }, item.showTitle && item.title); case 'input': return jsx(Input, { key: idx, mountPoint: popupsMountPoint, boundariesElement: popupsBoundariesElement, defaultValue: item.defaultValue, placeholder: item.placeholder // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onSubmit: value => dispatchCommand(item.onSubmit(value)) // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onBlur: value => dispatchCommand(item.onBlur(value)) }); case 'custom': { return item.render(editorView, idx, dispatchAnalyticsEvent); } case 'overflow-dropdown': // if an option has a confirmDialog, we need to replace its onClick handler // to set the state to show the confirm dialog // crudely done here to avoid greater coupling with DropdownMenuItem from `floating-toolbar` // which would need knowledge of indexes, showConfirmDialog etc. const options = item.options.map((option, optionIndex) => { if (!('type' in option) && option.confirmDialog) { const onClick = option.confirmDialog ? showConfirmDialog(idx, optionIndex) : option.onClick; return { ...option, onClick }; } return option; }); return jsx(Dropdown, { alignX: areAnyNewToolbarFlagsEnabled ? 'right' : undefined, key: idx, title: intl.formatMessage(commonMessages.viewMore), icon: jsx(ShowMoreHorizontalIcon, { label: "", spacing: "spacious" }), dispatchCommand: dispatchCommand, options: options, disabled: item.disabled, tooltip: item.tooltip, hideExpandIcon: true, mountPoint: popupsMountPoint, boundariesElement: popupsBoundariesElement, scrollableElement: popupsScrollableElement, dropdownWidth: item.dropdownWidth, showSelected: item.showSelected, buttonTestId: item.testId, editorView: editorView, setDisableParentScroll: scrollable ? setDisableScroll : undefined, dropdownListId: (item === null || item === void 0 ? void 0 : item.id) && `${item.id}-dropdownList`, alignDropdownWithToolbar: items.length === 1, onClick: item.onClick, areAnyNewToolbarFlagsEnabled: areAnyNewToolbarFlagsEnabled }); case 'dropdown': const DropdownIcon = item.icon; const BeforeIcon = item.iconBefore; return jsx(Dropdown, { key: idx, title: item.title, icon: DropdownIcon && jsx(DropdownIcon, { label: item.title }), iconBefore: BeforeIcon && jsx(BeforeIcon, { label: "" }), dispatchCommand: dispatchCommand, options: item.options, disabled: item.disabled, tooltip: item.tooltip, hideExpandIcon: item.hideExpandIcon, mountPoint: popupsMountPoint, boundariesElement: popupsBoundariesElement, scrollableElement: popupsScrollableElement, dropdownWidth: item.dropdownWidth, showSelected: item.showSelected, buttonTestId: item.testId, editorView: editorView, setDisableParentScroll: scrollable ? setDisableScroll : undefined, dropdownListId: (item === null || item === void 0 ? void 0 : item.id) && `${item.id}-dropdownList`, alignDropdownWithToolbar: items.length === 1, onToggle: item.onToggle, footer: item.footer, onMount: item.onMount, onClick: item.onClick, pulse: item.pulse, shouldFitContainer: item.shouldFitContainer, areAnyNewToolbarFlagsEnabled: areAnyNewToolbarFlagsEnabled }); case 'select': if (item.selectType === 'list') { const ariaLabel = item.title || item.placeholder; return jsx(Select, { key: idx, dispatchCommand: dispatchCommand, options: item.options, hideExpandIcon: item.hideExpandIcon // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion , mountPoint: scrollable ? mountRef.current : undefined, boundariesElement: popupsBoundariesElement, scrollableElement: popupsScrollableElement, defaultValue: item.defaultValue, placeholder: item.placeholder // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onChange: selected => dispatchCommand(item.onChange(selected)), ariaLabel: ariaLabel, filterOption: item.filterOption, setDisableParentScroll: scrollable ? setDisableScroll : undefined, classNamePrefix: 'floating-toolbar-select' }); } if (item.selectType === 'color') { return jsx(ColorPickerButton, { skipFocusButtonAfterPick: true, key: idx, isAriaExpanded: item.isAriaExpanded, title: item.title // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onChange: selected => { dispatchCommand(item.onChange(selected)); }, colorPalette: item.options, currentColor: item.defaultValue ? item.defaultValue.value : undefined, placement: "Panels", mountPoint: emojiAndColourPickerMountPoint, setDisableParentScroll: scrollable ? setDisableScroll : undefined // Currently in floating toolbar, color picker is only // used in panel and table cell background color. // Both uses same color palette. // That's why hard-coding hexToEditorBackgroundPaletteColor // and paletteColorTooltipMessages. // When we need to support different color palette // in floating toolbar, we need to set hexToPaletteColor // and paletteColorTooltipMessages in item options. , hexToPaletteColor: hexToEditorBackgroundPaletteColor, paletteColorTooltipMessages: backgroundPaletteTooltipMessages, returnEscToButton: item.returnEscToButton }); } if (item.selectType === 'emoji') { return jsx(EmojiPickerButton, { key: idx, editorView: editorView, title: item.title, providerFactory: providerFactory, isSelected: item.selected // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onChange: selected => dispatchCommand(item.onChange(selected)), mountPoint: emojiAndColourPickerMountPoint, popupsBoundariesElement: popupsBoundariesElement, setDisableParentScroll: scrollable ? setDisableScroll : undefined, pluginInjectionApi: api }); } return null; case 'extensions-placeholder': if (!editorView || !extensionsProvider) { return null; } return jsx(ExtensionsPlaceholder, { key: idx, node: node, editorView: editorView, extensionProvider: extensionsProvider, separator: item.separator, applyChangeToContextPanel: api === null || api === void 0 ? void 0 : (_api$contextPanel = api.contextPanel) === null || _api$contextPanel === void 0 ? void 0 : _api$contextPanel.actions.applyChange, extensionApi: api === null || api === void 0 ? void 0 : (_api$extension = api.extension) === null || _api$extension === void 0 ? void 0 : _api$extension.actions.api(), dispatchCommand: dispatchCommand, popupsMountPoint: popupsMountPoint, popupsBoundariesElement: popupsBoundariesElement, popupsScrollableElement: popupsScrollableElement, alignDropdownWithToolbar: items.length === 1, scrollable: scrollable, areAnyNewToolbarFlagsEnabled: areAnyNewToolbarFlagsEnabled }); case 'separator': if (areAnyNewToolbarFlagsEnabled) { return item.fullHeight ? jsx(Separator, { key: idx, fullHeight: true, areAnyNewToolbarFlagsEnabled: true }) : null; } return jsx(Separator, { key: idx, fullHeight: item.fullHeight, areAnyNewToolbarFlagsEnabled: false }); } }; const groupedItems = groupItems( // eslint-disable-next-line @atlassian/perf-linting/no-expensive-computations-in-render -- Ignored via go/ees017 (to be fixed) items.filter(item => !item.hidden), areAnyNewToolbarFlagsEnabled); return jsx(ButtonGroup, { testId: "editor-floating-toolbar-items" }, groupedItems.map((element, index) => { const isGroup = Array.isArray(element); if (isGroup) { return jsx("div", { // Ignored via go/ees005 // eslint-disable-next-line react/no-array-index-key key: index, css: areAnyNewToolbarFlagsEnabled ? buttonGroupStylesNew : buttonGroupStyles, role: "radiogroup", "aria-label": groupLabel !== null && groupLabel !== void 0 ? groupLabel : undefined, "data-testid": "editor-floating-toolbar-grouped-buttons" }, element.map(element => { const indexInAllItems = items.findIndex(item => item === element); return renderItem(element, indexInAllItems); })); } else { const indexInAllItems = items.findIndex(item => item === element); return renderItem(element, indexInAllItems); } })); }, (prevProps, nextProps) => { if (!nextProps.node) { return false; } // only rerender toolbar items if the node is different // otherwise it causes an issue where multiple popups stays open return !(prevProps.node.type !== nextProps.node.type || prevProps.node.attrs.localId !== nextProps.node.attrs.localId || !areSameItems(prevProps.items, nextProps.items) || !prevProps.mounted !== !nextProps.mounted); }); const buttonGroupStyles = css({ display: 'flex', gap: "var(--ds-space-050, 4px)" }); const buttonGroupStylesNew = css({ display: 'flex', gap: "var(--ds-space-075, 6px)" }); // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage const toolbarContainer = (areAnyNewToolbarFlagsEnabled, scrollable, hasSelect, firstElementIsSelect) => css({ backgroundColor: "var(--ds-surface-overlay, #FFFFFF)", borderRadius: "var(--ds-radius-small, 3px)", boxShadow: "var(--ds-shadow-overlay, 0px 8px 12px #1E1F2126, 0px 0px 1px #1E1F214f)", display: 'flex', // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography lineHeight: 1, boxSizing: 'border-box', // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors -- Ignored via go/DSP-18766 '& > div > div': { alignItems: 'center' } }, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 scrollable ? // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 css( // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 hasSelect ? // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 css({ height: '40px' }) : // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 css({ height: '32px' }), { overflow: 'hidden' }) : // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values areAnyNewToolbarFlagsEnabled ? // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values css({ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 padding: `${"var(--ds-space-0, 0px)"} 4px ${"var(--ds-space-0, 0px)"} 4px` }, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 firstElementIsSelect && // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 css({ paddingLeft: "var(--ds-space-050, 4px)" })) : // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 css({ padding: `${"var(--ds-space-050, 4px)"} ${"var(--ds-space-100, 8px)"}` }, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 firstElementIsSelect && // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 css({ paddingLeft: "var(--ds-space-050, 4px)" })), // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values areAnyNewToolbarFlagsEnabled ? // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values css({ minHeight: "var(--ds-space-500, 40px)" }) : undefined); // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage const toolbarOverflow = ({ scrollable, scrollDisabled, firstElementIsSelect, areAnyNewToolbarFlagsEnabled }) => css( // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 scrollable ? // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 css( // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 scrollDisabled ? // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 css({ overflow: 'hidden' }) : // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values css({ overflowX: 'auto', overflowY: 'hidden', // When scrollable is true, ScrollButtons will be shown, hence we want to hide show default horizontal scrollbar scrollbarWidth: 'none' }), { WebkitOverflowScrolling: 'touch', // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 padding: `${"var(--ds-space-050, 4px)"} 0 ${"var(--ds-space-050, 4px)"}`, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors -- Ignored via go/DSP-18766 '> div': { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 '> div:first-child': firstElementIsSelect ? // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 css({ marginLeft: "var(--ds-space-050, 4px)" }) : // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 css({ marginLeft: "var(--ds-space-100, 8px)" }), // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors -- Ignored via go/DSP-18766 '> div:last-child': { marginRight: "var(--ds-space-100, 8px)" } } }, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values areAnyNewToolbarFlagsEnabled ? // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values css({ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 padding: `${"var(--ds-space-0, 0px)"} 4px ${"var(--ds-space-600, 48px)"} 4px`, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors '> div': { minHeight: "var(--ds-space-500, 40px)", gap: "var(--ds-space-075, 6px)", // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors -- Ignored via go/DSP-18766 '> div:first-child': { marginLeft: 0 }, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors -- Ignored via go/DSP-18766 '> div:last-child': { marginRight: 0 } } }) : undefined) : // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 css({ display: 'flex' })); // eslint-disable-next-line @repo/internal/react/no-class-components class Toolbar extends Component { constructor(props) { super(props); _defineProperty(this, "shouldHandleArrowKeys", () => { var _this$props$items; //To prevent the keydown handling of arrow keys for custom toolbar items with 'disableArrowNavigation' prop enabled, //Usually the button which has menus or popups return !((_this$props$items = this.props.items) !== null && _this$props$items !== void 0 && _this$props$items.find(item => item.type === 'custom' && item.disableArrowNavigation)); }); _defineProperty(this, "handleEscape", event => { var _this$props$editorVie; // If any menu is open inside the floating toolbar 'Esc' key should not // focus the editorview. // Event can't be stopped as they are not childnodes of floating toolbar // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage const isDropdownOpen = !!document.querySelector('[data-role="droplistContent"]'); // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage const isSelectMenuOpen = !!document.querySelector('.floating-toolbar-select__menu'); if (isDropdownOpen || isSelectMenuOpen) { return; } (_this$props$editorVie = this.props.editorView) === null || _this$props$editorVie === void 0 ? void 0 : _this$props$editorVie.focus(); event.preventDefault(); event.stopPropagation(); }); _defineProperty(this, "captureMouseEvent", event => { var _this$props$items2; // Don't capture mouse event for custom toolbars e.g. insert hyperlink if (((_this$props$items2 = this.props.items) === null || _this$props$items2 === void 0 ? void 0 : _this$props$items2.length) === 1 && this.props.items[0].type === 'custom') { return; } // Prevents toolbar from closing when clicking on the toolbar itself and not on the buttons event.stopPropagation(); event.preventDefault(); }); _defineProperty(this, "isShortcutToFocusToolbar", event => { //Alt + F10 to reach first element in this floating toolbar return event.altKey && (event.key === 'F10' || event.keyCode === 121); }); _defineProperty(this, "doesNodeRequireAssitiveMessage", node => { // Code blocks have an assistive message to announce the content of the code block to screen readers, so we don't need to announce the floating toolbar for those nodes const nodesWithAlternativeRoles = ['codeBlock']; if (nodesWithAlternativeRoles.includes(node.type.name)) { return false; } return true; }); this.scrollContainerRef = /*#__PURE__*/React.createRef(); this.mountRef = /*#__PURE__*/React.createRef(); this.toolbarContainerRef = /*#__PURE__*/React.createRef(); this.state = { scrollDisabled: false, mounted: false }; } // remove any decorations added by toolbar buttons i.e danger and selected styling // this prevents https://product-fabric.atlassian.net/browse/ED-10207 resetStyling() { if (this.props.editorView) { var _this$props$api, _this$props$api$decor; const { state, dispatch } = this.props.editorView; (_this$props$api = this.props.api) === null || _this$props$api === void 0 ? void 0 : (_this$props$api$decor = _this$props$api.decorations) === null || _this$props$api$decor === void 0 ? void 0 : _this$props$api$decor.actions.removeDecoration(state, dispatch); } } setDisableScroll(disabled) { // wait before setting disabled state incase users jumping from one popup to another if (disabled) { requestAnimationFrame(() => { this.setState({ scrollDisabled: disabled }); }); } else { this.setState({ scrollDisabled: disabled }); } } componentDidMount() { this.setState({ mounted: true }); } componentDidUpdate(prevProps) { var _this$props; checkShouldForceFocusAndApply((_this$props = this.props) === null || _this$props === void 0 ? void 0 : _this$props.editorView); if (this.props.node !== prevProps.node) { this.resetStyling(); } } componentWillUnmount() { const { editorView } = this.props; if (editorView) { const { state: { tr }, dispatch } = editorView; dispatch(forceFocusSelector(null)(tr)); } this.resetStyling(); } render() { var _this$props$api2; const { items, className, node, intl, scrollable, mediaAssistiveMessage } = this.props; const areAnyNewToolbarFlagsEnabled = areToolbarFlagsEnabled(Boolean((_this$props$api2 = this.props.api) === null || _this$props$api2 === void 0 ? void 0 : _this$props$api2.toolbar)); if (!items || !items.length) { return null; } // Select has left padding of 4px to the border, everything else 8px const firstElementIsSelect = items[0].type === 'select'; const hasSelect = items.find(item => item.type === 'select' && item.selectType === 'list'); const shouldRenderAssistiveAnnouncer = expValEquals('editor_a11y_role_textbox', 'isEnabled', true) ? this.doesNodeRequireAssitiveMessage(node) : true; return jsx(React.Fragment, null, jsx(ToolbarArrowKeyNavigationProvider, { editorView: this.props.editorView, handleEscape: this.handleEscape, disableArrowKeyNavigation: !this.shouldHandleArrowKeys(), childComponentSelector: "[data-testid='editor-floating-toolbar']", isShortcutToFocusToolbar: this.isShortcutToFocusToolbar, intl: intl }, jsx("div", { ref: this.toolbarContainerRef, css: () => [toolbarContainer(areAnyNewToolbarFlagsEnabled, scrollable, hasSelect !== undefined, firstElementIsSelect)], "aria-label": intl.formatMessage(messages.floatingToolbarAriaLabel), role: "toolbar", "data-testid": "editor-floating-toolbar" // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766 , className: className, onMouseDown: areAnyNewToolbarFlagsEnabled ? this.captureMouseEvent : undefined }, shouldRenderAssistiveAnnouncer && jsx(Announcer, { text: mediaAssistiveMessage ? `${mediaAssistiveMessage}, ${intl.formatMessage(messages.floatingToolbarAnnouncer)}` : intl.formatMessage(messages.floatingToolbarAnnouncer), delay: 250 }), scrollable && areAnyNewToolbarFlagsEnabled && jsx(ScrollButton, { intl: intl, scrollContainerRef: this.scrollContainerRef, node: node, disabled: this.state.scrollDisabled, side: "left" }), jsx("div", { "data-testid": "floating-toolbar-items", ref: this.scrollContainerRef // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage , css: toolbarOverflow({ areAnyNewToolbarFlagsEnabled, scrollable, scrollDisabled: this.state.scrollDisabled, firstElementIsSelect }) }, jsx(ToolbarItems // Ignored via go/ees005 // eslint-disable-next-line react/jsx-props-no-spreading , _extends({}, this.props, { setDisableScroll: this.setDisableScroll.bind(this), mountRef: this.mountRef, mounted: this.state.mounted }))), scrollable && (areAnyNewToolbarFlagsEnabled ? jsx(ScrollButton, { intl: intl, scrollContainerRef: this.scrollContainerRef, node: node, disabled: this.state.scrollDisabled, side: "right" }) : jsx(ScrollButtons, { intl: intl, scrollContainerRef: this.scrollContainerRef, node: node, disabled: this.state.scrollDisabled, areAnyNewToolbarFlagsEnabled: areAnyNewToolbarFlagsEnabled }))), jsx("div", { ref: this.mountRef }))); } } // eslint-disable-next-line @typescript-eslint/ban-types const _default_1 = injectIntl(Toolbar); export default _default_1;