@atlaskit/renderer
Version:
Renderer component
850 lines (826 loc) • 45.8 kB
JavaScript
"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;