UNPKG

@atlaskit/editor-core

Version:

A package contains Atlassian editor core functionality

229 lines (228 loc) 13.4 kB
import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; /** * @jsxRuntime classic * @jsx jsx */ import React, { useEffect, useMemo, useRef, useState } from 'react'; // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled, @typescript-eslint/consistent-type-imports -- Ignored via go/DSP-18766; jsx required at runtime for @jsxRuntime classic import { jsx } from '@emotion/react'; import { getBrowserInfo } from '@atlaskit/editor-common/browser'; import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks'; import { SSRRenderMeasure } from '@atlaskit/editor-common/performance/ssr-measures'; import { ContextPanelWidthProvider } from '@atlaskit/editor-common/ui'; import { useSharedPluginStateSelector } from '@atlaskit/editor-common/use-shared-plugin-state-selector'; import { FULL_PAGE_EDITOR_TOOLBAR_HEIGHT } from '@atlaskit/editor-shared-styles'; 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 { getPrimaryToolbarComponents } from '../../Toolbar/getPrimaryToolbarComponents'; import { FullPageContentArea } from './FullPageContentArea'; import { FullPageToolbar } from './FullPageToolbar'; import { FullPageToolbarNext } from './FullPageToolbarNext'; import { fullPageEditorWrapper } from './StyledComponents'; var SSR_TRACE_SEGMENT_NAME = 'reactEditorView/fullPageAppearance'; var useShowKeyline = function useShowKeyline(contentAreaRef) { var _useState = useState(false), _useState2 = _slicedToArray(_useState, 2), showKeyline = _useState2[0], setShowKeyline = _useState2[1]; useEffect(function () { var _contentAreaRef$curre; if (!((_contentAreaRef$curre = contentAreaRef.current) !== null && _contentAreaRef$curre !== void 0 && _contentAreaRef$curre.contentArea)) { return; } var browser = getBrowserInfo(); var intersection = new IntersectionObserver(function (_ref) { var _ref2 = _slicedToArray(_ref, 1), entry = _ref2[0]; setShowKeyline(!entry.isIntersecting && entry.boundingClientRect.top < entry.intersectionRect.top); }, { root: undefined, // Safari seems to miss events (on fast scroll) sometimes due // to differences in IntersectionObserver behaviour between browsers. // By lowering the threshold a little it gives Safari more // time to catch these events. threshold: browser.safari ? 0.98 : 1 }); intersection.observe(contentAreaRef.current.contentArea); return function () { intersection.disconnect(); }; }, [contentAreaRef]); return showKeyline; }; var hasCustomComponents = function hasCustomComponents(components) { if (!components) { return false; } if ('before' in components) { return Array.isArray(components.before) && components.before.length > 0 || !!components.before || Array.isArray(components.after) && components.after.length > 0 || !!components.after; } return true; }; export var FullPageEditor = function FullPageEditor(props) { var _scrollContentContain, _scrollContentContain2, _scrollContentContain3, _wrapperElementRef$cu; // Should be always the first statement in the component var firstRenderStartTimestampRef = useRef(performance.now()); var wrapperElementRef = useMemo(function () { return props.innerRef; }, [props.innerRef]); var scrollContentContainerRef = useRef(null); var showKeyline = useShowKeyline(scrollContentContainerRef); var editorAPI = props.editorAPI; var state = useSharedPluginStateWithSelector(editorAPI, ['primaryToolbar', 'interaction', 'editorViewMode', 'toolbar'], function (states) { var _states$primaryToolba, _states$interactionSt, _states$editorViewMod, _states$toolbarState; return { primaryToolbarComponents: (_states$primaryToolba = states.primaryToolbarState) === null || _states$primaryToolba === void 0 ? void 0 : _states$primaryToolba.components, interactionState: (_states$interactionSt = states.interactionState) === null || _states$interactionSt === void 0 ? void 0 : _states$interactionSt.interactionState, editorViewMode: (_states$editorViewMod = states.editorViewModeState) === null || _states$editorViewMod === void 0 ? void 0 : _states$editorViewMod.mode, contextualFormattingModeOverride: (_states$toolbarState = states.toolbarState) === null || _states$toolbarState === void 0 ? void 0 : _states$toolbarState.contextualFormattingModeOverride }; }); // Markdown Mode forces `'always-pinned'` while in source / preview view // (no PM selection to anchor a floating toolbar to). The user's docking // pref alone is not enough to decide whether to mount the primary toolbar // in that case — the override has to short-circuit the hide gate below. var forcePrimaryToolbarPinned = state.contextualFormattingModeOverride === 'always-pinned' && fg('platform_editor_toolbar_mode_override'); var interactionState = state.interactionState; var primaryToolbarState = getPrimaryToolbarComponents(editorAPI, state.primaryToolbarComponents); var hasHadInteraction = interactionState !== 'hasNotHadInteraction'; var toolbarDocking = useSharedPluginStateSelector(editorAPI, 'selectionToolbar.toolbarDocking', { disabled: fg('platform_editor_use_preferences_plugin') }); if (!fg('platform_editor_use_preferences_plugin')) { if (!toolbarDocking) { var _editorAPI$selectionT, _editorAPI$selectionT2; // This is a workaround for the rendering issue with the selection toolbar // where using useSharedPluginStateSelector or useSharedPluginState the state are not // available when the editor is first loaded. and cause the toolbar to blink. var defaultDocking = props.__livePage ? 'none' : 'top'; toolbarDocking = (_editorAPI$selectionT = editorAPI === null || editorAPI === void 0 || (_editorAPI$selectionT2 = editorAPI.selectionToolbar) === null || _editorAPI$selectionT2 === void 0 || (_editorAPI$selectionT2 = _editorAPI$selectionT2.sharedState.currentState()) === null || _editorAPI$selectionT2 === void 0 ? void 0 : _editorAPI$selectionT2.toolbarDocking) !== null && _editorAPI$selectionT !== void 0 ? _editorAPI$selectionT : defaultDocking; } } var _ref3 = useSharedPluginStateSelector(editorAPI, 'userPreferences.preferences', { disabled: !fg('platform_editor_use_preferences_plugin') }) || {}, toolbarDockingPosition = _ref3.toolbarDockingPosition; if (fg('platform_editor_use_preferences_plugin')) { if (!toolbarDockingPosition) { var _editorAPI$userPrefer, _editorAPI$userPrefer2; // This is a workaround for the rendering issue with the selection toolbar // when using useSharedPluginStateWithSelector the state is not yet // available when the editor is first loaded. // This causes the toolbar to blink creating a layout shift. var defaultDockingPosition = props.__livePage ? 'none' : 'top'; toolbarDockingPosition = (_editorAPI$userPrefer = editorAPI === null || editorAPI === void 0 || (_editorAPI$userPrefer2 = editorAPI.userPreferences) === null || _editorAPI$userPrefer2 === void 0 || (_editorAPI$userPrefer2 = _editorAPI$userPrefer2.actions.getUserPreferences()) === null || _editorAPI$userPrefer2 === void 0 ? void 0 : _editorAPI$userPrefer2.toolbarDockingPosition) !== null && _editorAPI$userPrefer !== void 0 ? _editorAPI$userPrefer : defaultDockingPosition; } } var primaryToolbarComponents = props.primaryToolbarComponents; if (Array.isArray(primaryToolbarState === null || primaryToolbarState === void 0 ? void 0 : primaryToolbarState.components) && Array.isArray(primaryToolbarComponents)) { primaryToolbarComponents = primaryToolbarState.components.concat(primaryToolbarComponents); } var isEditorToolbarHidden = state.editorViewMode === 'view'; var customPrimaryToolbarComponents = props.customPrimaryToolbarComponents; if (editorExperiment('platform_editor_controls', 'variant1', { exposure: true })) { if (fg('platform_editor_use_preferences_plugin')) { // need to check if the toolbarDockingPosition is set to 'none' or 'top' if (toolbarDockingPosition === 'none' && !forcePrimaryToolbarPinned) { primaryToolbarComponents = []; if (!hasCustomComponents(customPrimaryToolbarComponents)) { isEditorToolbarHidden = true; } } } else { if (toolbarDocking === 'none' && !forcePrimaryToolbarPinned) { primaryToolbarComponents = []; if (!hasCustomComponents(customPrimaryToolbarComponents)) { isEditorToolbarHidden = true; } } } } var isToolbarAIFCEnabled = Boolean(editorAPI === null || editorAPI === void 0 ? void 0 : editorAPI.toolbar); var popupsBoundariesElement = props.popupsBoundariesElement || (scrollContentContainerRef === null || scrollContentContainerRef === void 0 || (_scrollContentContain = scrollContentContainerRef.current) === null || _scrollContentContain === void 0 ? void 0 : _scrollContentContain.containerArea) || undefined; return jsx(SSRRenderMeasure, { segmentName: SSR_TRACE_SEGMENT_NAME, startTimestampRef: firstRenderStartTimestampRef, onSSRMeasure: props.onSSRMeasure }, jsx(ContextPanelWidthProvider, null, jsx("div", { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766 css: fullPageEditorWrapper // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766 , className: "akEditor", ref: wrapperElementRef, style: { '--ak-editor-fullpage-toolbar-height': // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values FULL_PAGE_EDITOR_TOOLBAR_HEIGHT(isToolbarAIFCEnabled) } }, !isEditorToolbarHidden && (isToolbarAIFCEnabled ? jsx(FullPageToolbarNext, { disabled: !!props.disabled || !hasHadInteraction && expValEquals('platform_editor_default_toolbar_state', 'isEnabled', true), toolbarDockingPosition: toolbarDockingPosition !== null && toolbarDockingPosition !== void 0 ? toolbarDockingPosition : toolbarDocking, beforeIcon: props.primaryToolbarIconBefore, editorAPI: editorAPI, editorView: props.editorView, popupsMountPoint: props.popupsMountPoint, popupsBoundariesElement: props.popupsBoundariesElement, popupsScrollableElement: props.popupsScrollableElement, showKeyline: showKeyline, customPrimaryToolbarComponents: props.customPrimaryToolbarComponents }) : jsx(FullPageToolbar, { appearance: props.appearance, editorAPI: editorAPI, beforeIcon: props.primaryToolbarIconBefore, collabEdit: props.collabEdit, containerElement: (_scrollContentContain2 = (_scrollContentContain3 = scrollContentContainerRef.current) === null || _scrollContentContain3 === void 0 ? void 0 : _scrollContentContain3.scrollContainer) !== null && _scrollContentContain2 !== void 0 ? _scrollContentContain2 : null, customPrimaryToolbarComponents: props.customPrimaryToolbarComponents, disabled: !!props.disabled, dispatchAnalyticsEvent: props.dispatchAnalyticsEvent, editorActions: props.editorActions, editorDOMElement: props.editorDOMElement // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion , editorView: props.editorView // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion , eventDispatcher: props.eventDispatcher, hasMinWidth: props.enableToolbarMinWidth, popupsBoundariesElement: props.popupsBoundariesElement, popupsMountPoint: props.popupsMountPoint, popupsScrollableElement: props.popupsScrollableElement, primaryToolbarComponents: primaryToolbarComponents, providerFactory: props.providerFactory, showKeyline: showKeyline, featureFlags: props.featureFlags })), jsx(FullPageContentArea, { editorAPI: editorAPI, ref: scrollContentContainerRef, appearance: props.appearance, contentComponents: props.contentComponents, contextPanel: props.contextPanel, customContentComponents: props.customContentComponents, disabled: props.disabled, dispatchAnalyticsEvent: props.dispatchAnalyticsEvent, editorActions: props.editorActions, editorDOMElement: props.editorDOMElement // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion , editorView: props.editorView, eventDispatcher: props.eventDispatcher, popupsBoundariesElement: popupsBoundariesElement, popupsMountPoint: props.popupsMountPoint, popupsScrollableElement: props.popupsScrollableElement, providerFactory: props.providerFactory, wrapperElement: (_wrapperElementRef$cu = wrapperElementRef === null || wrapperElementRef === void 0 ? void 0 : wrapperElementRef.current) !== null && _wrapperElementRef$cu !== void 0 ? _wrapperElementRef$cu : null, pluginHooks: props.pluginHooks, featureFlags: props.featureFlags, isEditorToolbarHidden: isEditorToolbarHidden, viewMode: state.editorViewMode, hasHadInteraction: hasHadInteraction, contentMode: props.contentMode })))); };