UNPKG

@atlaskit/editor-plugin-toolbar

Version:

Toolbar plugin for @atlaskit/editor-core

147 lines 9.5 kB
import React, { useCallback, useMemo } from 'react'; import { useIntl } from 'react-intl'; import { ACTION_SUBJECT, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics'; import { isSSR } from '@atlaskit/editor-common/core-utils'; import { ErrorBoundary } from '@atlaskit/editor-common/error-boundary'; import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks'; import { logException } from '@atlaskit/editor-common/monitoring'; import { EditorToolbarProvider, EditorToolbarUIProvider, shouldShowSelectionToolbar } from '@atlaskit/editor-common/toolbar'; import { Popup } from '@atlaskit/editor-common/ui'; import { calculateToolbarPositionTrackHead, calculateToolbarPositionOnCellSelection } from '@atlaskit/editor-common/utils'; import { isOfflineMode } from '@atlaskit/editor-plugin-connectivity'; import { AllSelection, TextSelection } from '@atlaskit/editor-prosemirror/state'; import { akEditorFloatingDialogZIndex } from '@atlaskit/editor-shared-styles'; import { ToolbarSection, ToolbarButtonGroup, ToolbarDropdownItemSection, useToolbarUI } from '@atlaskit/editor-toolbar'; import { ToolbarModelRenderer } from '@atlaskit/editor-toolbar-model'; import { fg } from '@atlaskit/platform-feature-flags'; import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals'; import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments'; import { SELECTION_TOOLBAR_LABEL } from '../consts'; import { getKeyboardNavigationConfig } from './keyboard-config'; import { getDomRefFromSelection } from './utils'; var isToolbarComponent = function isToolbarComponent(component) { return component.type === 'toolbar' && component.key === 'inline-text-toolbar'; }; var usePluginState = function usePluginState(api) { return useSharedPluginStateWithSelector(api, ['connectivity', 'userPreferences', 'toolbar', 'selection', 'userIntent', 'editorViewMode'], function (state) { var _state$connectivitySt, _state$userPreference, _state$toolbarState, _state$toolbarState2, _state$selectionState, _state$userIntentStat, _state$editorViewMode; return { connectivityStateMode: (_state$connectivitySt = state.connectivityState) === null || _state$connectivitySt === void 0 ? void 0 : _state$connectivitySt.mode, editorToolbarDockingPreference: (_state$userPreference = state.userPreferencesState) === null || _state$userPreference === void 0 || (_state$userPreference = _state$userPreference.preferences) === null || _state$userPreference === void 0 ? void 0 : _state$userPreference.toolbarDockingPosition, shouldShowToolbar: (_state$toolbarState = state.toolbarState) === null || _state$toolbarState === void 0 ? void 0 : _state$toolbarState.shouldShowToolbar, selectedNode: (_state$toolbarState2 = state.toolbarState) === null || _state$toolbarState2 === void 0 ? void 0 : _state$toolbarState2.selectedNode, selection: (_state$selectionState = state.selectionState) === null || _state$selectionState === void 0 ? void 0 : _state$selectionState.selection, currentUserIntent: (_state$userIntentStat = state.userIntentState) === null || _state$userIntentStat === void 0 ? void 0 : _state$userIntentStat.currentUserIntent, editorViewMode: (_state$editorViewMode = state.editorViewModeState) === null || _state$editorViewMode === void 0 ? void 0 : _state$editorViewMode.mode }; }); }; var useOnPositionCalculated = function useOnPositionCalculated(editorView) { var onPositionCalculated = useCallback(function (position) { try { // Show special position on cell selection only when editor controls experiment is enabled var isEditorControlsEnabled = expValEquals('platform_editor_controls', 'cohort', 'variant1'); var isCellSelection = ('$anchorCell' in editorView.state.selection); if (isCellSelection && isEditorControlsEnabled) { return calculateToolbarPositionOnCellSelection(SELECTION_TOOLBAR_LABEL)(editorView, position); } return calculateToolbarPositionTrackHead(SELECTION_TOOLBAR_LABEL)(editorView, position); } catch (error) { logException(error, { location: 'editor-plugin-toolbar/selectionToolbar' }); return position; } }, [editorView]); return onPositionCalculated; }; export var SelectionToolbar = function SelectionToolbar(_ref) { var _api$toolbar$actions$, _api$toolbar, _api$toolbar2; var api = _ref.api, editorView = _ref.editorView, mountPoint = _ref.mountPoint, disableSelectionToolbarWhenPinned = _ref.disableSelectionToolbarWhenPinned; var _usePluginState = usePluginState(api), connectivityStateMode = _usePluginState.connectivityStateMode, editorToolbarDockingPreference = _usePluginState.editorToolbarDockingPreference, currentUserIntent = _usePluginState.currentUserIntent, shouldShowToolbar = _usePluginState.shouldShowToolbar, editorViewMode = _usePluginState.editorViewMode; var contextualFormattingEnabled = (_api$toolbar$actions$ = api === null || api === void 0 || (_api$toolbar = api.toolbar) === null || _api$toolbar === void 0 ? void 0 : _api$toolbar.actions.contextualFormattingMode()) !== null && _api$toolbar$actions$ !== void 0 ? _api$toolbar$actions$ : 'always-pinned'; var selectionToolbarConfigEnabled = shouldShowSelectionToolbar(contextualFormattingEnabled, editorToolbarDockingPreference); var intl = useIntl(); var components = api === null || api === void 0 || (_api$toolbar2 = api.toolbar) === null || _api$toolbar2 === void 0 ? void 0 : _api$toolbar2.actions.getComponents(); var toolbar = components === null || components === void 0 ? void 0 : components.find(function (component) { return isToolbarComponent(component); }); var keyboardNavigation = useMemo(function () { return getKeyboardNavigationConfig(editorView, intl, api); }, [editorView, intl, api]); var _useToolbarUI = useToolbarUI(), isDisabled = _useToolbarUI.isDisabled; var isOffline = isOfflineMode(connectivityStateMode); var isTextSelection = !editorView.state.selection.empty && editorView.state.selection instanceof TextSelection; var isAllSelection = !editorView.state.selection.empty && editorView.state.selection instanceof AllSelection; var isCellSelection = !editorView.state.selection.empty && '$anchorCell' in editorView.state.selection; var onPositionCalculated = useOnPositionCalculated(editorView); if (selectionToolbarConfigEnabled && disableSelectionToolbarWhenPinned || !components || !toolbar) { return null; } if (!(isTextSelection || isCellSelection || isAllSelection) || currentUserIntent === 'dragging' || !shouldShowToolbar || currentUserIntent === 'blockMenuOpen' && editorExperiment('platform_editor_block_menu', true) || // hide toolbar when user intent is not default, except when it's dragHandleSelected without cell selection currentUserIntent && currentUserIntent !== 'default' && !(currentUserIntent === 'dragHandleSelected' && !isCellSelection) || isSSR()) { return null; } return /*#__PURE__*/React.createElement(Popup // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , { offset: [0, 10], target: getDomRefFromSelection(editorView), onPositionCalculated: onPositionCalculated, mountTo: mountPoint, zIndex: fg('platform_editor_sel_toolbar_stacking_fix') ? akEditorFloatingDialogZIndex : undefined }, /*#__PURE__*/React.createElement(EditorToolbarProvider, { editorView: editorView, editorToolbarDockingPreference: editorToolbarDockingPreference, editorViewMode: editorViewMode !== null && editorViewMode !== void 0 ? editorViewMode : 'edit', isOffline: isOffline }, /*#__PURE__*/React.createElement(EditorToolbarUIProvider, { api: api, isDisabled: isDisabled // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , fireAnalyticsEvent: function fireAnalyticsEvent(payload) { var _api$analytics; api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.fireAnalyticsEvent(payload); }, keyboardNavigation: keyboardNavigation }, /*#__PURE__*/React.createElement(ToolbarModelRenderer, { toolbar: toolbar, components: components // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , fallbacks: { section: ToolbarSection, menuSection: ToolbarDropdownItemSection, group: ToolbarButtonGroup } })))); }; export var SelectionToolbarWithErrorBoundary = function SelectionToolbarWithErrorBoundary(_ref2) { var _api$analytics2; var api = _ref2.api, editorView = _ref2.editorView, mountPoint = _ref2.mountPoint, disableSelectionToolbarWhenPinned = _ref2.disableSelectionToolbarWhenPinned; return /*#__PURE__*/React.createElement(ErrorBoundary, { component: ACTION_SUBJECT.TOOLBAR, componentId: ACTION_SUBJECT_ID.SELECTION_TOOLBAR, dispatchAnalyticsEvent: api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions.fireAnalyticsEvent, fallbackComponent: null }, /*#__PURE__*/React.createElement(SelectionToolbar, { api: api, editorView: editorView, mountPoint: mountPoint, disableSelectionToolbarWhenPinned: disableSelectionToolbarWhenPinned })); };