UNPKG

@atlaskit/editor-plugin-floating-toolbar

Version:

Floating toolbar plugin for @atlaskit/editor-core

741 lines (730 loc) • 33.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 Announcer from '@atlaskit/editor-common/announcer'; import { areSameItems } from '@atlaskit/editor-common/floating-toolbar'; import messages from '@atlaskit/editor-common/floating-toolbar/messages'; import Button from '@atlaskit/editor-common/FloatingToolbar/Button'; import Separator from '@atlaskit/editor-common/FloatingToolbar/Separator'; import commonMessages from '@atlaskit/editor-common/messages'; import { areToolbarFlagsEnabled } from '@atlaskit/editor-common/toolbar-flag-check'; import { backgroundPaletteTooltipMessages } from '@atlaskit/editor-common/ui-color/ColorPalette/paletteMessagesTokenModeNames'; import ColorPickerButton from '@atlaskit/editor-common/ui-menu/ColorPickerButton'; import { ToolbarArrowKeyNavigationProvider } from '@atlaskit/editor-common/ui-menu/ToolbarArrowKeyNavigationProvider'; import { hexToEditorBackgroundPaletteColor } from '@atlaskit/editor-palette/background'; import ShowMoreHorizontalIcon from '@atlaskit/icon/core/show-more-horizontal'; import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled'; 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 = 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, hasNewContentOnTriggerClick: item.hasNewContentOnTriggerClick, ariaHasPopup: item.ariaHasPopup, tabIndex: item.tabIndex, isRadioButton: item.isRadioButton, ariaLabel: item === null || item === void 0 ? void 0 : item.ariaLabel, 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, { popupsBoundariesElement, popupsMountPoint, popupsScrollableElement, scrollable, setDisableParentScroll: scrollable ? setDisableScroll : undefined }); } 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') { var _item$hexToPaletteCol, _item$paletteColorToo; return jsx(ColorPickerButton, { skipFocusButtonAfterPick: true, key: idx, isAriaExpanded: item.isAriaExpanded, hideExpandIcon: item.hideExpandIcon, 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)); }, cols: item.cols, colorPalette: item.options, currentColor: item.defaultValue ? item.defaultValue.value : undefined, placement: "Panels", mountPoint: emojiAndColourPickerMountPoint, setDisableParentScroll: scrollable ? setDisableScroll : undefined, hexToPaletteColor: isExperimentEnabled('platform_editor_lovability_dividers') ? (_item$hexToPaletteCol = item.hexToPaletteColor) !== null && _item$hexToPaletteCol !== void 0 ? _item$hexToPaletteCol : hexToEditorBackgroundPaletteColor : hexToEditorBackgroundPaletteColor, paletteColorTooltipMessages: isExperimentEnabled('platform_editor_lovability_dividers') ? (_item$paletteColorToo = item.paletteColorTooltipMessages) !== null && _item$paletteColorToo !== void 0 ? _item$paletteColorToo : backgroundPaletteTooltipMessages : 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 || prevProps.popupsBoundariesElement !== nextProps.popupsBoundariesElement || prevProps.popupsMountPoint !== nextProps.popupsMountPoint || prevProps.popupsScrollableElement !== nextProps.popupsScrollableElement || prevProps.scrollable !== nextProps.scrollable || prevProps.setDisableScroll !== nextProps.setDisableScroll || !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)" }); const toolbarContainerBase = css({ 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/design-system/consistent-css-prop-usage const toolbarContainer = (areAnyNewToolbarFlagsEnabled, scrollable, hasSelect, firstElementIsSelect, // See `FloatingToolbarConfig.containerSurface`: 'none' is for a single custom item that // already renders its own complete surface, so this wrapper's own surface is omitted. containerSurface = 'default') => css( // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 containerSurface === 'none' ? undefined : { 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)" }, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 containerSurface === 'none' ? // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 css({ padding: "var(--ds-space-0, 0px)" }) : 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:nth-last-child(1 of :not(:where([popover], dialog)))': { 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:nth-last-child(1 of :not(:where([popover], dialog)))': { 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, "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 }); } }); _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); }); 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); } } 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'); 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: () => [toolbarContainerBase, toolbarContainer(areAnyNewToolbarFlagsEnabled, scrollable, hasSelect !== undefined, firstElementIsSelect, this.props.containerSurface)], "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 }, 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, 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/no-restricted-types const _default_1 = injectIntl(Toolbar); export default _default_1;