UNPKG

@atlaskit/renderer

Version:
850 lines (826 loc) • 45.8 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.NORMAL_SEVERITY_THRESHOLD = exports.DEGRADED_SEVERITY_THRESHOLD = void 0; exports.Renderer = Renderer; exports.default = exports.RendererWithAnalytics = exports.RendererFunctionalComponent = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireWildcard(require("react")); var _schemaDefault = require("@atlaskit/adf-schema/schema-default"); var _providerFactory = require("@atlaskit/editor-common/provider-factory"); var _ui = require("@atlaskit/editor-common/ui"); var _experiments = require("@atlaskit/tmp-editor-statsig/experiments"); var _react2 = require("@emotion/react"); var _browser = require("@atlaskit/editor-common/browser"); var _nesting = require("@atlaskit/editor-common/nesting"); var _performanceMeasures = require("@atlaskit/editor-common/performance-measures"); var _measureRender = require("@atlaskit/editor-common/performance/measure-render"); var _navigation = require("@atlaskit/editor-common/performance/navigation"); var _useScrollToBlock = require("../hooks/useScrollToBlock"); var _utils = require("@atlaskit/editor-common/utils"); var _platformFeatureFlags = require("@atlaskit/platform-feature-flags"); var _types = require("@atlaskit/analytics-listeners/types"); var _analyticsNamespacedContext = require("@atlaskit/analytics-namespaced-context"); var _analytics = require("@atlaskit/editor-common/analytics"); var _normalizeFeatureFlags = require("@atlaskit/editor-common/normalize-feature-flags"); var _v = _interopRequireDefault(require("uuid/v4")); var _ = require("../../"); var _analyticsContext = _interopRequireDefault(require("../../analytics/analyticsContext")); var _events = require("../../analytics/events"); var _EditorMediaClientProvider = require("../../react/utils/EditorMediaClientProvider"); var _links = require("../../react/utils/links"); var _rendererContext = require("../../renderer-context"); var _utils2 = require("../../utils"); var _RendererActionsContext = require("../RendererActionsContext"); var _SmartCardStorage = require("../SmartCardStorage"); var _activeHeaderIdProvider = require("../active-header-id-provider"); var _annotations = require("../annotations"); var _ErrorBoundary = require("./ErrorBoundary"); var _breakoutSsr = require("./breakout-ssr"); var _clickToEdit = require("./click-to-edit"); var _countNodes = require("./count-nodes"); var _style = require("./style"); var _truncatedWrapper = require("./truncated-wrapper"); var _ValidationContext = require("./ValidationContext"); var _RendererStyleContainer = require("./RendererStyleContainer"); var _getBaseFontSize = require("./get-base-font-size"); var _rendererHelper = require("./rendererHelper"); var _useMemoFromPropsDerivative = require("./useMemoFromPropsDerivative"); var _PortalContext = require("./PortalContext"); var _expValEqualsNoExposure = require("@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure"); var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals"); var _analyticsUtils = require("./analytics-utils"); var _excluded = ["portal"]; function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /** * @jsxRuntime classic * @jsx jsx */ // eslint-disable-next-line @typescript-eslint/consistent-type-imports, @atlaskit/ui-styling-standard/use-compiled -- emotion jsx pragma; go/DSP-18766 // oxlint-ignore @typescript-eslint/consistent-type-imports -- classic @jsx jsx factory + jsx.JSX.Element types // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead var NORMAL_SEVERITY_THRESHOLD = exports.NORMAL_SEVERITY_THRESHOLD = 2000; var DEGRADED_SEVERITY_THRESHOLD = exports.DEGRADED_SEVERITY_THRESHOLD = 3000; // we want to calculate all the table widths (which causes reflows) after the renderer has finished loading to mitigate performance impact var TABLE_INFO_TIMEOUT = 10000; var RENDER_EVENT_SAMPLE_RATE = 0.2; var packageName = "@atlaskit/renderer"; var packageVersion = "132.0.1"; var setAsQueryContainerStyles = (0, _react2.css)({ containerName: 'ak-renderer-wrapper', containerType: 'inline-size' }); var handleMouseTripleClickInTables = function handleMouseTripleClickInTables(event) { var _parentElement, _parentElement2; var browser = (0, _browser.getBrowserInfo)(); if (browser.ios || browser.android) { return; } var badBrowser = browser.chrome || browser.safari; var tripleClick = event.detail >= 3; if (!(badBrowser && tripleClick)) { return; } var selection = window.getSelection(); if (!selection) { return; } var type = selection.type, anchorNode = selection.anchorNode, focusNode = selection.focusNode; var rangeSelection = Boolean(type === 'Range' && anchorNode && focusNode); if (!rangeSelection) { return; } // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting var target = event.target; var tableCell = target.closest('td,th'); var clickedInCell = Boolean(tableCell); if (!clickedInCell) { return; } // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion var anchorInCell = tableCell.contains(anchorNode); // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion var focusInCell = tableCell.contains(focusNode); var selectionStartsOrEndsOutsideClickedCell = !(anchorInCell && focusInCell); if (!selectionStartsOrEndsOutsideClickedCell) { return; } // Ensure that selecting text in the renderer doesn't trigger onUnhandledClick // This logic originated in jira-frontend: // src/packages/issue/issue-view/src/views/field/rich-text/rich-text-inline-edit-view.js // The selection is required to be checked in `onMouseDown` and here. If not here, a new // selection isn't reported; if not in `onMouseDown`, a click outside the selection will // return an empty selection, which will erroneously fire onUnhandledClick. var elementToSelect = anchorInCell ? // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion (_parentElement = anchorNode.parentElement) === null || _parentElement === void 0 ? void 0 : _parentElement.closest('div,p') : focusInCell ? // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion (_parentElement2 = focusNode.parentElement) === null || _parentElement2 === void 0 ? void 0 : _parentElement2.closest('div,p') : tableCell; if (elementToSelect) { selection.selectAllChildren(elementToSelect); } }; /** * Handle clicks inside renderer. If the click isn't on media, in the media picker, or on a * link, call the onUnhandledClick eventHandler (which in Jira for example, may switch the * renderer out for the editor). * @param event Click event anywhere inside renderer * @param props * @param mouseDownSelection * @example */ var handleWrapperOnClick = function handleWrapperOnClick(event, props, mouseDownSelection) { var _props$eventHandlers; // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting var targetElement = event.target; handleMouseTripleClickInTables(event); // ED-14862: When a user triple clicks to select a line of content inside a // a table cell, but the browser incorrectly moves the selection start or end into // a different table cell, we manually set the selection back to within the original // table cell the user intended to target if (!((_props$eventHandlers = props.eventHandlers) !== null && _props$eventHandlers !== void 0 && _props$eventHandlers.onUnhandledClick)) { return; } if (!(targetElement instanceof window.Element)) { return; } // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting var rendererWrapper = event.currentTarget; var isInteractiveElementInTree = (0, _utils2.findInTree)(targetElement, rendererWrapper, _clickToEdit.isInteractiveElement); if (isInteractiveElementInTree) { return; } // Ensure that selecting text in the renderer doesn't trigger onUnhandledClick // This logic originated in jira-frontend: // src/packages/issue/issue-view/src/views/field/rich-text/rich-text-inline-edit-view.js // The selection is required to be checked in `onMouseDown` and here. If not here, a new // selection isn't reported; if not in `onMouseDown`, a click outside the selection will // return an empty selection, which will erroneously fire onUnhandledClick. var windowSelection = window.getSelection(); var selection = windowSelection !== null ? windowSelection.toString() : undefined; var hasSelection = selection && selection.length !== 0; var hasSelectionMouseDown = mouseDownSelection.current && mouseDownSelection.current.length !== 0; var allowEditBasedOnSelection = !hasSelection && !hasSelectionMouseDown; if (allowEditBasedOnSelection) { props.eventHandlers.onUnhandledClick(event); } }; var RendererFunctionalComponent = exports.RendererFunctionalComponent = function RendererFunctionalComponent(props) { var createAnalyticsEvent = props.createAnalyticsEvent; var mouseDownSelection = (0, _react.useRef)(undefined); var providerFactory = (0, _react.useMemo)(function () { return props.dataProviders || new _providerFactory.ProviderFactory(); }, [props.dataProviders]); var _useRendererContext = (0, _rendererContext.useRendererContext)(), nestedRendererType = _useRendererContext.nestedRendererType; var createRendererContext = (0, _react.useMemo)(function () { return function (featureFlags, isTopLevelRenderer) { var normalizedFeatureFlags = (0, _normalizeFeatureFlags.normalizeFeatureFlags)(featureFlags); return { featureFlags: normalizedFeatureFlags, isTopLevelRenderer: isTopLevelRenderer === undefined, // Propagate nestedRendererType into the inner RendererContextProvider so that // React components inside the renderer (e.g. Colgroup) can read it via // useRendererContext(). Without this, the inner provider overwrites the outer // AKRendererWrapper context and nestedRendererType becomes undefined. nestedRendererType: nestedRendererType }; }; }, [nestedRendererType]); var fireAnalyticsEventOld = (0, _react.useCallback)(function (event) { var createAnalyticsEvent = props.createAnalyticsEvent; if (createAnalyticsEvent) { var channel = _types.FabricChannel.editor; createAnalyticsEvent(event).fire(channel); } }, [props]); var fireAnalyticsEventNew = (0, _react.useCallback)(function (event) { if (createAnalyticsEvent) { var channel = _types.FabricChannel.editor; createAnalyticsEvent(event).fire(channel); } }, [createAnalyticsEvent]); var _fireAnalyticsEvent = (0, _experiments.editorExperiment)('platform_renderer_fix_analytics_memo_callback', true, { exposure: true }) ? fireAnalyticsEventNew : fireAnalyticsEventOld; var deriveSerializerProps = (0, _react.useCallback)(function (props) { var _props$startPos; var stickyHeaders = props.stickyHeaders ? props.stickyHeaders === true ? {} : props.stickyHeaders : undefined; var annotationProvider = props.annotationProvider; var allowAnnotationsDraftMode = Boolean(annotationProvider && annotationProvider.inlineComment && annotationProvider.inlineComment.allowDraftMode); var _createRendererContex = createRendererContext(props.featureFlags, props.isTopLevelRenderer), featureFlags = _createRendererContex.featureFlags; return { startPos: (_props$startPos = props.startPos) !== null && _props$startPos !== void 0 ? _props$startPos : 0, providers: providerFactory, eventHandlers: props.eventHandlers, extensionHandlers: props.extensionHandlers, portal: props.portal, objectContext: _objectSpread(_objectSpread({ adDoc: props.shouldRemoveEmptySpaceAroundContent ? (0, _rendererHelper.removeEmptySpaceAroundContent)(props.document) : props.document, schema: props.schema }, props.rendererContext), {}, { nestedRendererType: nestedRendererType }), appearance: props.appearance, contentMode: props.contentMode, onSetLinkTarget: props.onSetLinkTarget, disableHeadingIDs: props.disableHeadingIDs, disableActions: props.disableActions, allowHeadingAnchorLinks: props.allowHeadingAnchorLinks, allowColumnSorting: props.allowColumnSorting, fireAnalyticsEvent: _fireAnalyticsEvent, shouldOpenMediaViewer: props.shouldOpenMediaViewer, allowAltTextOnImages: props.allowAltTextOnImages, stickyHeaders: stickyHeaders, allowMediaLinking: props.media && props.media.allowLinking, surroundTextNodesWithTextWrapper: allowAnnotationsDraftMode, media: props.media, emojiResourceConfig: props.emojiResourceConfig, smartLinks: props.smartLinks, extensionViewportSizes: props.extensionViewportSizes, getExtensionHeight: props.getExtensionHeight, allowCopyToClipboard: props.allowCopyToClipboard, allowWrapCodeBlock: props.allowWrapCodeBlock, allowCustomPanels: props.allowCustomPanels, allowAnnotations: props.allowAnnotations, allowSelectAllTrap: props.allowSelectAllTrap, allowPlaceholderText: props.allowPlaceholderText, nodeComponents: props.nodeComponents, allowWindowedCodeBlock: featureFlags === null || featureFlags === void 0 ? void 0 : featureFlags.allowWindowedCodeBlock, isInsideOfInlineExtension: props.isInsideOfInlineExtension, isPresentational: props.UNSTABLE_isPresentational, textHighlighter: props.textHighlighter || props.UNSTABLE_textHighlighter, allowTableAlignment: props.UNSTABLE_allowTableAlignment, allowTableResizing: props.UNSTABLE_allowTableResizing, disableTableOverflowShadow: props.disableTableOverflowShadow, allowFixedColumnWidthOption: props.allowFixedColumnWidthOption, shouldDisplayExtensionAsInline: props.shouldDisplayExtensionAsInline }; }, [createRendererContext, providerFactory, _fireAnalyticsEvent, nestedRendererType]); var serializer = (0, _useMemoFromPropsDerivative.useMemoFromPropsDerivative)(function (serializerProps) { var _props$createSerializ, _props$createSerializ2; return (_props$createSerializ = (_props$createSerializ2 = props.createSerializer) === null || _props$createSerializ2 === void 0 ? void 0 : _props$createSerializ2.call(props, serializerProps)) !== null && _props$createSerializ !== void 0 ? _props$createSerializ : new _.ReactSerializer(serializerProps); }, deriveSerializerProps, props); var localRef = (0, _react.useRef)(null); var editorRef = props.innerRef || localRef; // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead var id = (0, _react.useMemo)(function () { return (0, _v.default)(); }, []); var renderedMeasurementDistortedDurationMonitor = (0, _react.useMemo)(function () { return (0, _measureRender.getDistortedDurationMonitor)(); }, []); // we are doing this to ensure it runs as // early as possible in the React lifecycle // to avoid any other side effects var measureStarted = (0, _react.useRef)(false); var startAnalyticsMeasure = function startAnalyticsMeasure() { (0, _performanceMeasures.startMeasure)("Renderer Render Time: ".concat(id)); }; if (!measureStarted.current) { startAnalyticsMeasure(); measureStarted.current = true; } var anchorLinkAnalytics = (0, _react.useCallback)(function () { var hash = window.location.hash && decodeURIComponent(window.location.hash.slice(1)); var disableHeadingIDs = props.disableHeadingIDs; if (!disableHeadingIDs && hash && editorRef && editorRef.current instanceof HTMLElement) { // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- anchor navigation uses document.getElementById for hash targets var anchorLinkElement = document.getElementById(hash); if (anchorLinkElement && editorRef.current.contains(anchorLinkElement)) { _fireAnalyticsEvent({ action: _analytics.ACTION.VIEWED, actionSubject: _analytics.ACTION_SUBJECT.ANCHOR_LINK, attributes: { platform: _events.PLATFORM.WEB, mode: _events.MODE.RENDERER }, eventType: _analytics.EVENT_TYPE.UI }); } } }, [props.disableHeadingIDs, editorRef, _fireAnalyticsEvent]); var getSchema = (0, _react.useMemo)(function () { return function (schema, adfStage) { if (schema) { return schema; } return (0, _schemaDefault.getSchemaBasedOnStage)(adfStage); }; }, []); var onMouseDownEditView = function onMouseDownEditView() { var windowSelection = window.getSelection(); mouseDownSelection.current = windowSelection !== null ? windowSelection.toString() : undefined; }; var dataProviders = props.dataProviders, analyticsEventSeverityTracking = props.analyticsEventSeverityTracking; (0, _react.useEffect)(function () { var rafID; var heightWidthAnalyticsSetTimeoutID; var heightWidthAnalyticsRicID; var heightWidthAnalyticsRafID; var handleAnalytics = function handleAnalytics() { _fireAnalyticsEvent({ action: _analytics.ACTION.STARTED, actionSubject: _analytics.ACTION_SUBJECT.RENDERER, attributes: { platform: _events.PLATFORM.WEB }, eventType: _analytics.EVENT_TYPE.UI }); rafID = requestAnimationFrame(function () { (0, _performanceMeasures.stopMeasure)("Renderer Render Time: ".concat(id), function (duration) { var _analyticsEventSeveri, _analyticsEventSeveri2; var forceSeverityTracking = typeof analyticsEventSeverityTracking === 'undefined' && (0, _utils.shouldForceTracking)(); var severity = !!forceSeverityTracking || analyticsEventSeverityTracking !== null && analyticsEventSeverityTracking !== void 0 && analyticsEventSeverityTracking.enabled ? (0, _utils.getAnalyticsEventSeverity)(duration, (_analyticsEventSeveri = analyticsEventSeverityTracking === null || analyticsEventSeverityTracking === void 0 ? void 0 : analyticsEventSeverityTracking.severityNormalThreshold) !== null && _analyticsEventSeveri !== void 0 ? _analyticsEventSeveri : NORMAL_SEVERITY_THRESHOLD, (_analyticsEventSeveri2 = analyticsEventSeverityTracking === null || analyticsEventSeverityTracking === void 0 ? void 0 : analyticsEventSeverityTracking.severityDegradedThreshold) !== null && _analyticsEventSeveri2 !== void 0 ? _analyticsEventSeveri2 : DEGRADED_SEVERITY_THRESHOLD) : undefined; var isTTRTrackingExplicitlyDisabled = (analyticsEventSeverityTracking === null || analyticsEventSeverityTracking === void 0 ? void 0 : analyticsEventSeverityTracking.enabled) === false; if (!isTTRTrackingExplicitlyDisabled) { var event = { action: _analytics.ACTION.RENDERED, actionSubject: _analytics.ACTION_SUBJECT.RENDERER, attributes: { platform: _events.PLATFORM.WEB, duration: duration, // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion distortedDuration: renderedMeasurementDistortedDurationMonitor.distortedDuration, ttfb: (0, _navigation.getResponseEndTime)(), nodes: (0, _countNodes.countNodes)(props.document), nestedRendererType: (0, _experiments.editorExperiment)('platform_synced_block', true) ? nestedRendererType : undefined, severity: severity }, eventType: _analytics.EVENT_TYPE.OPERATIONAL }; _fireAnalyticsEvent(event); if ((0, _expValEquals.expValEquals)('platform_editor_sample_renderer_rendered_event', 'isEnabled', true) && Math.random() < RENDER_EVENT_SAMPLE_RATE) { _fireAnalyticsEvent(_objectSpread(_objectSpread({}, event), {}, { action: _analytics.ACTION.RENDERED_SAMPLED })); } } // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion renderedMeasurementDistortedDurationMonitor.cleanup(); }); anchorLinkAnalytics(); }); // send statistics about the heights/widths of the tables on the page for alerting heightWidthAnalyticsSetTimeoutID = setTimeout(function () { var requestIdleCallbackFn = function requestIdleCallbackFn() { var _props$innerRef; var renderer = (_props$innerRef = props.innerRef) === null || _props$innerRef === void 0 || (_props$innerRef = _props$innerRef.current) === null || _props$innerRef === void 0 ? void 0 : _props$innerRef.querySelector('.ak-renderer-document'); if (renderer) { var payload = (0, _analyticsUtils.getWidthInfoPayload)(renderer); if (payload) { _fireAnalyticsEvent(payload); } if ((0, _platformFeatureFlags.fg)('platform_editor_table_height_analytics_event')) { var payloadHeight = (0, _analyticsUtils.getHeightInfoPayload)(renderer); if (payloadHeight) { _fireAnalyticsEvent(payloadHeight); } } } }; if (window && typeof window.requestIdleCallback === 'function') { heightWidthAnalyticsRicID = window.requestIdleCallback(requestIdleCallbackFn); } else if (window && typeof window.requestAnimationFrame === 'function') { // requestIdleCallback is not supported in safari, fallback to requestAnimationFrame heightWidthAnalyticsRafID = window.requestAnimationFrame(requestIdleCallbackFn); } }, TABLE_INFO_TIMEOUT); }; handleAnalytics(); return function () { if (rafID) { window.cancelAnimationFrame(rafID); } if (heightWidthAnalyticsSetTimeoutID) { window.clearTimeout(heightWidthAnalyticsSetTimeoutID); } if (heightWidthAnalyticsRafID) { window.cancelAnimationFrame(heightWidthAnalyticsRafID); } if (heightWidthAnalyticsRicID) { window.cancelIdleCallback(heightWidthAnalyticsRicID); } // if this is the ProviderFactory which was created in constructor // it's safe to destroy it on Renderer unmount // updated to match existing class component if (!dataProviders) { providerFactory.destroy(); } }; // we are going to ignore this because I'm doing this on purpose // having a dependency array means we run stopMeasure twice per render // eslint-disable-next-line react-hooks/exhaustive-deps }, []); var rendererContext = (0, _react.useMemo)(function () { return _objectSpread(_objectSpread({}, createRendererContext(props.featureFlags, props.isTopLevelRenderer)), {}, { timeZone: props.timeZone }); }, [props.featureFlags, props.isTopLevelRenderer, createRendererContext, props.timeZone]); (0, _useScrollToBlock.useScrollToBlock)(editorRef, props.document, props.scrollToBlock); try { var _rendererContext$feat, _props$media; var schema = getSchema(props.schema, props.adfStage); var allowTableInPanel = (0, _nesting.isPanelNestingTableSupported)(schema); var validationOverrides = allowTableInPanel ? _objectSpread(_objectSpread({}, props.validationOverrides), {}, { allowTableInPanel: true }) : props.validationOverrides; var _renderDocument = (0, _.renderDocument)(props.shouldRemoveEmptySpaceAroundContent ? (0, _rendererHelper.removeEmptySpaceAroundContent)(props.document) : props.document, serializer, schema, props.adfStage, props.useSpecBasedValidator, id, _fireAnalyticsEvent, props.unsupportedContentLevelsTracking, props.appearance, props.includeNodesCountInStats, props.skipValidation, validationOverrides), result = _renderDocument.result, stat = _renderDocument.stat, pmDoc = _renderDocument.pmDoc; if (props.onComplete) { props.onComplete(stat); } var rendererOutput = (0, _react2.jsx)(_rendererContext.RendererContextProvider, { value: rendererContext }, (0, _react2.jsx)(_activeHeaderIdProvider.ActiveHeaderIdProvider, { value: (0, _links.getActiveHeadingId)(props.allowHeadingAnchorLinks) }, (0, _react2.jsx)(_analyticsContext.default.Provider, { // eslint-disable-next-line @atlassian/perf-linting/no-inline-context-value, @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) value: { fireAnalyticsEvent: function fireAnalyticsEvent(event) { return _fireAnalyticsEvent(event); } } }, (0, _react2.jsx)(_SmartCardStorage.Provider, null, (0, _react2.jsx)(_providerFactory.ProviderFactoryProvider, { value: providerFactory }, (0, _react2.jsx)(RendererWrapper, { allowAnnotations: props.allowAnnotations, appearance: props.appearance, contentMode: props.contentMode || 'standard', allowNestedHeaderLinks: (0, _links.isNestedHeaderLinksEnabled)(props.allowHeadingAnchorLinks), allowColumnSorting: props.allowColumnSorting, allowCopyToClipboard: props.allowCopyToClipboard, allowWrapCodeBlock: props.allowWrapCodeBlock, allowCustomPanels: props.allowCustomPanels, allowPlaceholderText: props.allowPlaceholderText, useBlockRenderForCodeBlock: (_rendererContext$feat = rendererContext.featureFlags.useBlockRenderForCodeBlock) !== null && _rendererContext$feat !== void 0 ? _rendererContext$feat : true, addTelepointer: props.addTelepointer, innerRef: editorRef // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onClick: function onClick(event) { return handleWrapperOnClick(event, props, mouseDownSelection); }, onMouseDown: onMouseDownEditView, ssr: (_props$media = props.media) === null || _props$media === void 0 ? void 0 : _props$media.ssr, isInsideOfInlineExtension: props.isInsideOfInlineExtension, isTopLevelRenderer: rendererContext.isTopLevelRenderer, shouldRemoveEmptySpaceAroundContent: props.shouldRemoveEmptySpaceAroundContent, allowRendererContainerStyles: props.allowRendererContainerStyles }, props.enableSsrInlineScripts || props.noOpSSRInlineScript ? (0, _react2.jsx)(_breakoutSsr.BreakoutSSRInlineScript, { noOpSSRInlineScript: Boolean(props.noOpSSRInlineScript) }) : null, (0, _react2.jsx)(RendererActionsInternalUpdater, { doc: pmDoc, schema: schema, onAnalyticsEvent: _fireAnalyticsEvent }, result))))))); var rendererResult = props.truncated ? (0, _react2.jsx)(_truncatedWrapper.TruncatedWrapper, { height: props.maxHeight, fadeHeight: props.fadeOutHeight }, rendererOutput) : rendererOutput; return (0, _react2.jsx)(_react.Fragment, null, rendererResult); } catch (e) { var _rendererContext$feat2; if (props.onError) { props.onError(e); } return (0, _react2.jsx)(RendererWrapper, { allowAnnotations: props.allowAnnotations, appearance: props.appearance, contentMode: props.contentMode || 'standard', allowCopyToClipboard: props.allowCopyToClipboard, allowWrapCodeBlock: props.allowWrapCodeBlock, allowPlaceholderText: props.allowPlaceholderText, allowColumnSorting: props.allowColumnSorting, allowNestedHeaderLinks: (0, _links.isNestedHeaderLinksEnabled)(props.allowHeadingAnchorLinks), useBlockRenderForCodeBlock: (_rendererContext$feat2 = rendererContext.featureFlags.useBlockRenderForCodeBlock) !== null && _rendererContext$feat2 !== void 0 ? _rendererContext$feat2 : true, addTelepointer: props.addTelepointer // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onClick: function onClick(event) { return handleWrapperOnClick(event, props, mouseDownSelection); }, isTopLevelRenderer: rendererContext.isTopLevelRenderer, allowRendererContainerStyles: props.allowRendererContainerStyles }, (0, _react2.jsx)(_ui.UnsupportedBlock, null)); } }; var RendererFunctionalComponentMemoized = /*#__PURE__*/_react.default.memo(RendererFunctionalComponent); var RendererFunctionalComponentWithPortalContext = /*#__PURE__*/_react.default.memo(function (props) { // If nodeComponents are provided, we don't remove portal from props and use context instead, // because we can't guarantee compatibility with existing Atlaskit Renderer consumers. if (props.nodeComponents) { return /*#__PURE__*/_react.default.createElement(RendererFunctionalComponentMemoized, props); } var portal = props.portal, propsWithoutPortal = (0, _objectWithoutProperties2.default)(props, _excluded); return (0, _react2.jsx)(_PortalContext.PortalContext.Provider, { value: portal }, /*#__PURE__*/_react.default.createElement(RendererFunctionalComponent, propsWithoutPortal)); }); /** * Top-level ADF renderer: renders document content with analytics and validation context. * @param props Renderer configuration and document tree. */ function Renderer(props) { var _props$isTopLevelRend; var _React$useContext = _react.default.useContext(_annotations.AnnotationsPositionContext), startPos = _React$useContext.startPos; var _useRendererContext2 = (0, _rendererContext.useRendererContext)(), isTopLevelRenderer = _useRendererContext2.isTopLevelRenderer; var _ref = (0, _react.useContext)(_ValidationContext.ValidationContext) || {}, skipValidation = _ref.skipValidation, allowNestedTables = _ref.allowNestedTables; var validationOverrides = (0, _react.useMemo)(function () { return { allowNestedTables: allowNestedTables }; }, [allowNestedTables]); return (0, _react2.jsx)(RendererFunctionalComponentWithPortalContext // Ignored via go/ees005 // eslint-disable-next-line react/jsx-props-no-spreading , (0, _extends2.default)({}, props, { startPos: startPos, isTopLevelRenderer: (_props$isTopLevelRend = props.isTopLevelRenderer) !== null && _props$isTopLevelRend !== void 0 ? _props$isTopLevelRend : isTopLevelRenderer, skipValidation: skipValidation, validationOverrides: validationOverrides })); } // Usage notes: // Used by Confluence for View page renderer // For the nested renderers - see RendererWithAnnotationSelection. var RendererWithAnalytics = exports.RendererWithAnalytics = /*#__PURE__*/_react.default.memo(function (props) { return (0, _react2.jsx)(_analyticsNamespacedContext.FabricEditorAnalyticsContext // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , { data: { appearance: (0, _utils.getAnalyticsAppearance)(props.appearance), packageName: packageName, packageVersion: packageVersion, componentName: 'renderer', // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead editorSessionId: (0, _v.default)() } }, (0, _react2.jsx)(_ui.WithCreateAnalyticsEvent // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , { render: function render(createAnalyticsEvent) { // `IntlErrorBoundary` only captures Internationalisation errors, leaving others for `ErrorBoundary`. return (0, _react2.jsx)(_ErrorBoundary.ErrorBoundary, { component: _analytics.ACTION_SUBJECT.RENDERER, rethrowError: true, fallbackComponent: null, createAnalyticsEvent: createAnalyticsEvent }, (0, _react2.jsx)(_ui.IntlErrorBoundary, null, (0, _react2.jsx)(Renderer // Ignored via go/ees005 // eslint-disable-next-line react/jsx-props-no-spreading , (0, _extends2.default)({}, props, { createAnalyticsEvent: createAnalyticsEvent })))); } })); }); var RendererWrapper = /*#__PURE__*/_react.default.memo(function (props) { var allowColumnSorting = props.allowColumnSorting, allowNestedHeaderLinks = props.allowNestedHeaderLinks, innerRef = props.innerRef, appearance = props.appearance, contentMode = props.contentMode, children = props.children, onClick = props.onClick, onMouseDown = props.onMouseDown, useBlockRenderForCodeBlock = props.useBlockRenderForCodeBlock, addTelepointer = props.addTelepointer, ssr = props.ssr, isInsideOfInlineExtension = props.isInsideOfInlineExtension, allowTableResizing = props.allowTableResizing, isTopLevelRenderer = props.isTopLevelRenderer, allowRendererContainerStyles = props.allowRendererContainerStyles; var createTelepointer = function createTelepointer() { // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- telepointer span for collaborative presence var telepointer = document.createElement('span'); telepointer.textContent = "\u200B"; telepointer.id = _style.TELEPOINTER_ID; return telepointer; }; var initialUpdate = _react.default.useRef(true); var _useRendererContext3 = (0, _rendererContext.useRendererContext)(), nestedRendererType = _useRendererContext3.nestedRendererType; (0, _react.useEffect)(function () { // We must check if window is defined, if it isn't we are in a SSR environment // and we don't want to add the telepointer if (typeof window !== 'undefined' && addTelepointer && innerRef !== null && innerRef !== void 0 && innerRef.current) { // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion var _renderer = innerRef.current.querySelector('.ak-renderer-document'); if (initialUpdate.current) { var lastChild = _renderer.lastChild; lastChild && lastChild.appendChild(createTelepointer()); } var mutateTelepointer = function mutateTelepointer(mutations) { mutations.forEach(function (mutation, _index) { var _mutation$addedNodes$, _mutation$removedNode; if (initialUpdate.current) { var oldTelepointer = _renderer.querySelector("#".concat(_style.TELEPOINTER_ID)); if (oldTelepointer) { oldTelepointer.remove(); } var _lastChild = _renderer.lastChild; _lastChild && _lastChild.appendChild(createTelepointer()); initialUpdate.current = false; } if (mutation.type === 'characterData') { var parentNode = mutation.target.parentElement; if (parentNode) { var _oldTelepointer = _renderer.querySelector("#".concat(_style.TELEPOINTER_ID)); if (_oldTelepointer) { _oldTelepointer.remove(); } // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion parentNode.appendChild(createTelepointer()); } } /** * When streaming ADF content, we may receive mutations where nodes get * replaced, rather than have characterData updated. * * Telepointer changes will also cause a childList mutation, so we manually ignore it. * Telepointer changes are always a singular node-adds or node-removes. */ if (mutation.type === 'childList' && !(mutation.addedNodes.length === 1 && ((_mutation$addedNodes$ = mutation.addedNodes[0]) === null || _mutation$addedNodes$ === void 0 ? void 0 : _mutation$addedNodes$.id) === _style.TELEPOINTER_ID || mutation.removedNodes.length === 1 && ((_mutation$removedNode = mutation.removedNodes[0]) === null || _mutation$removedNode === void 0 ? void 0 : _mutation$removedNode.id) === _style.TELEPOINTER_ID)) { var _lastChild2 = _renderer.lastChild; if (_lastChild2) { /** * We want to place telepointer inside content (which has data-renderer-start-pos) and * inside lines in codeblocks (which have data-ds--code--row). */ var contentElements = _lastChild2.querySelectorAll('[data-renderer-start-pos],[data-ds--code--row]'); var lastElement = contentElements[contentElements.length - 1]; var _oldTelepointer2 = _renderer.querySelector("#".concat(_style.TELEPOINTER_ID)); if (lastElement) { _oldTelepointer2 === null || _oldTelepointer2 === void 0 || _oldTelepointer2.remove(); lastElement === null || lastElement === void 0 || lastElement.appendChild(createTelepointer()); } else { _oldTelepointer2 === null || _oldTelepointer2 === void 0 || _oldTelepointer2.remove(); _lastChild2 === null || _lastChild2 === void 0 || _lastChild2.appendChild(createTelepointer()); } } } }); }; var observer = new MutationObserver(mutateTelepointer); observer.observe(innerRef.current, { characterData: true, attributes: false, childList: true, subtree: true }); return function () { return observer.disconnect(); }; } }, [innerRef, addTelepointer]); var renderer = (0, _react2.jsx)(_ui.WidthProvider // eslint-disable-next-line @atlaskit/design-system/no-unsafe-style-overrides, @atlaskit/ui-styling-standard/no-classname-prop -- legacy renderer wrapper appearance classes , { className: "ak-renderer-wrapper is-".concat(appearance), "data-appearance": appearance, shouldCheckExistingValue: isInsideOfInlineExtension }, (0, _react2.jsx)(_ui.BaseTheme, { baseFontSize: (0, _getBaseFontSize.getBaseFontSize)(appearance, contentMode) }, (0, _react2.jsx)(_EditorMediaClientProvider.EditorMediaClientProvider, { ssr: ssr }, (0, _react2.jsx)(_RendererStyleContainer.RendererStyleContainer, { innerRef: innerRef, onClick: onClick, onMouseDown: onMouseDown, appearance: appearance, contentMode: contentMode, allowNestedHeaderLinks: allowNestedHeaderLinks, allowColumnSorting: !!allowColumnSorting, useBlockRenderForCodeBlock: useBlockRenderForCodeBlock, allowAnnotations: props.allowAnnotations, allowTableResizing: allowTableResizing, allowRendererContainerStyles: allowRendererContainerStyles, isInsideSyncBlock: nestedRendererType === 'syncedBlock' }, children)))); // We can only make the wrapper div query container when we have a known width. // This is also required for SSR to work correctly. As WidthProvider/WithConsumer will not have the correct width during SSR. // // allowRendererContainerStyles is not needed for comment container styling as container should always be set for comments if (appearance === 'comment' && isTopLevelRenderer && (0, _platformFeatureFlags.fg)('platform-ssr-table-resize')) { return (0, _react2.jsx)("div", { css: setAsQueryContainerStyles }, renderer); } // We are setting this wrapper div as query container conditionally. // Only apply container-type = inline-size when having a known width in full-page/full-width/comment mode. // Otherwise when appearance is unspecified the renderer size is decided by the content. // In this case we can't set the container-type = inline-size as it will collapse width to 0. return (appearance === 'full-page' || appearance === 'full-width' || ((0, _expValEqualsNoExposure.expValEqualsNoExposure)('editor_tinymce_full_width_mode', 'isEnabled', true) || (0, _expValEquals.expValEquals)('confluence_max_width_content_appearance', 'isEnabled', true)) && appearance === 'max') && // In case of having excerpt-include on page there are multiple renderers nested. // Make sure only the root renderer is set to be query container. isTopLevelRenderer && allowRendererContainerStyles && (0, _platformFeatureFlags.fg)('platform-ssr-table-resize') ? (0, _react2.jsx)("div", { css: setAsQueryContainerStyles }, renderer) : renderer; }); var RootRendererContext = /*#__PURE__*/_react.default.createContext(null); function RendererActionsInternalUpdater(_ref2) { var children = _ref2.children, doc = _ref2.doc, schema = _ref2.schema, onAnalyticsEvent = _ref2.onAnalyticsEvent; var rootRendererContextValue = _react.default.useContext(RootRendererContext); var actions = (0, _react.useContext)(_RendererActionsContext.RendererContext); var rendererRef = (0, _react.useRef)(null); // This doc is used by the renderer actions when applying comments to the document. // (via hand crafted steps based on non prosemirror based position calculations) // It is set to the root renderer's doc as otherwise the resulting document will // be incorrect (nested renderers use a fake document which represents a subset // of the actual document). var _doc; if ((0, _experiments.editorExperiment)('comment_on_bodied_extensions', true) && rootRendererContextValue) { // If rootRendererContextValue is set -- we are inside a nested renderer // and should always use the doc from the root renderer _doc = rootRendererContextValue.doc; } else { // If rootRendererContextValue is not set -- we are in the root renderer // and set the doc to the current doc. _doc = doc; } (0, _react.useLayoutEffect)(function () { if (_doc) { actions._privateRegisterRenderer(rendererRef, _doc, schema, onAnalyticsEvent); } else { actions._privateUnregisterRenderer(); } return function () { return actions._privateUnregisterRenderer(); }; }, [actions, schema, _doc, onAnalyticsEvent]); if ((0, _experiments.editorExperiment)('comment_on_bodied_extensions', true)) { return ( // eslint-disable-next-line @atlassian/perf-linting/no-inline-context-value, @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) (0, _react2.jsx)(RootRendererContext.Provider, { value: { doc: _doc } }, children) ); } return children; } // Usage notes: // Used by Confluence for nested renderers // For the View page renderer - see RendererWithAnalytics var RendererWithAnnotationSelection = function RendererWithAnnotationSelection(props) { var allowAnnotations = props.allowAnnotations, adfDocument = props.document; var localRef = _react.default.useRef(null); var innerRef = props.innerRef || localRef; // @see https://hello.jira.atlassian.cloud/browse/EDITOR-3389 if (props.appearance === 'max' && !(0, _expValEquals.expValEquals)('editor_tinymce_full_width_mode', 'isEnabled', true) && !(0, _expValEquals.expValEquals)('confluence_max_width_content_appearance', 'isEnabled', true)) { props.appearance = 'full-width'; } if (!allowAnnotations) { // Ignored via go/ees005 // eslint-disable-next-line react/jsx-props-no-spreading return (0, _react2.jsx)(RendererWithAnalytics, (0, _extends2.default)({ innerRef: innerRef }, props)); } return (0, _react2.jsx)(_RendererActionsContext.RendererActionsContext, null, (0, _react2.jsx)(_annotations.AnnotationsWrapper, { rendererRef: innerRef, adfDocument: adfDocument, annotationProvider: props.annotationProvider, isNestedRender: true }, (0, _react2.jsx)(RendererWithAnalytics, (0, _extends2.default)({ innerRef: innerRef // Ignored via go/ees005 // eslint-disable-next-line react/jsx-props-no-spreading }, props, { featureFlags: props.featureFlags })))); }; // eslint-disable-next-line @repo/internal/deprecations/deprecation-ticket-required -- Ignored via go/ED-25883 /* @deprecated using this version of the renderer causes the RendererActions to inaccessible from any consumers */ var _default = exports.default = RendererWithAnnotationSelection;