@atlaskit/renderer
Version:
Renderer component
392 lines (390 loc) • 18.9 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
/**
* @jsxRuntime classic
* @jsx jsx
*/
/* eslint-disable jsdoc/check-tag-names */
import { Fragment, useState, useMemo, useEffect } from 'react';
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
import { jsx } from '@emotion/react';
import { useSmartCardContext } from '@atlaskit/link-provider';
import { Card, getObjectAri, getObjectIconUrl, getObjectName } from '@atlaskit/smart-card';
import { isWithinPreviewPanelIFrame } from '@atlaskit/linking-common/utils';
import { useSmartLinkActions } from '@atlaskit/smart-card/hooks';
import { CardSSR } from '@atlaskit/smart-card/ssr';
import { HoverLinkOverlay, UnsupportedInline } from '@atlaskit/editor-common/ui';
import { fg } from '@atlaskit/platform-feature-flags';
import { AnalyticsContext } from '@atlaskit/analytics-next';
import { componentWithCondition } from '@atlaskit/platform-feature-flags-react';
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
import { SmartLinkDraggable, SMART_LINK_DRAG_TYPES, SMART_LINK_APPEARANCE } from '@atlaskit/editor-smart-link-draggable';
import { useProvider } from '@atlaskit/editor-common/provider-factory';
import { CardErrorBoundary } from './fallback';
import { withSmartCardStorage } from '../../ui/SmartCardStorage';
import { getCardClickHandler } from '../utils/getCardClickHandler';
import { useInlineAnnotationProps } from '../../ui/annotations/element/useInlineAnnotationProps';
import { usePortal } from '../../ui/Renderer/PortalContext';
import { extractSmartLinkEmbed } from '@atlaskit/link-extractors';
var HoverLinkOverlayNoop = function HoverLinkOverlayNoop(props) {
return jsx(Fragment, null, props.children);
};
var HoverLinkOverlayWithCondition = componentWithCondition(function () {
return editorExperiment('platform_editor_preview_panel_linking_exp', true, {
exposure: true
});
}, HoverLinkOverlay, HoverLinkOverlayNoop);
var OverlayWithCardContext = function OverlayWithCardContext(_ref) {
var _cardContext$value2, _cardContext$value3, _cardContext$value3$i, _cardContext$value4;
var rendererAppearance = _ref.rendererAppearance,
isResolvedViewRendered = _ref.isResolvedViewRendered,
url = _ref.url,
fireAnalyticsEvent = _ref.fireAnalyticsEvent,
children = _ref.children;
var cardContext = useSmartCardContext();
// Note: useSmartLinkActions throws without smart card context. Using it here is safe
// because we checked cardContext availability in the parent component
var actions = useSmartLinkActions({
url: url,
appearance: 'inline'
});
var preview = useMemo(function () {
return actions.find(function (action) {
return action.id === 'preview-content';
});
}, [actions]);
var fireHoverLabelAEP = function fireHoverLabelAEP(previewType) {
if (fireAnalyticsEvent) {
var _cardContext$value, _urlState$details$met, _urlState$details, _urlState$details$met2, _urlState$details2;
var store = cardContext === null || cardContext === void 0 || (_cardContext$value = cardContext.value) === null || _cardContext$value === void 0 ? void 0 : _cardContext$value.store;
var urlState = store === null || store === void 0 ? void 0 : store.getState()[url || ''];
fireAnalyticsEvent({
action: ACTION.CLICKED,
actionSubject: ACTION_SUBJECT.SMART_LINK,
actionSubjectId: ACTION_SUBJECT_ID.HOVER_LABEL,
eventType: EVENT_TYPE.UI,
attributes: {
previewType: previewType,
destinationProduct: (_urlState$details$met = urlState === null || urlState === void 0 || (_urlState$details = urlState.details) === null || _urlState$details === void 0 || (_urlState$details = _urlState$details.meta) === null || _urlState$details === void 0 ? void 0 : _urlState$details.product) !== null && _urlState$details$met !== void 0 ? _urlState$details$met : null,
destinationSubproduct: (_urlState$details$met2 = urlState === null || urlState === void 0 || (_urlState$details2 = urlState.details) === null || _urlState$details2 === void 0 || (_urlState$details2 = _urlState$details2.meta) === null || _urlState$details2 === void 0 ? void 0 : _urlState$details2.subproduct) !== null && _urlState$details$met2 !== void 0 ? _urlState$details$met2 : null
}
});
}
};
var cardState = cardContext === null || cardContext === void 0 || (_cardContext$value2 = cardContext.value) === null || _cardContext$value2 === void 0 || (_cardContext$value2 = _cardContext$value2.store) === null || _cardContext$value2 === void 0 ? void 0 : _cardContext$value2.getState()[url || ''];
var ari = getObjectAri(cardState === null || cardState === void 0 ? void 0 : cardState.details);
var name = getObjectName(cardState === null || cardState === void 0 ? void 0 : cardState.details);
var iconUrl = getObjectIconUrl(cardState === null || cardState === void 0 ? void 0 : cardState.details);
// Get resolved URL from card state, fallback to original URL if not available
var resolvedUrl = url;
if (expValEquals('platform_hover_card_preview_panel', 'cohort', 'test')) {
var _cardState$details;
var cardStateUrl = cardState !== null && cardState !== void 0 && (_cardState$details = cardState.details) !== null && _cardState$details !== void 0 && _cardState$details.data && 'url' in cardState.details.data ? cardState.details.data.url : undefined;
resolvedUrl = cardStateUrl || url;
}
var isPanelAvailable = ari && (cardContext === null || cardContext === void 0 || (_cardContext$value3 = cardContext.value) === null || _cardContext$value3 === void 0 || (_cardContext$value3$i = _cardContext$value3.isPreviewPanelAvailable) === null || _cardContext$value3$i === void 0 ? void 0 : _cardContext$value3$i.call(_cardContext$value3, {
ari: ari
}));
var openPreviewPanel = cardContext === null || cardContext === void 0 || (_cardContext$value4 = cardContext.value) === null || _cardContext$value4 === void 0 ? void 0 : _cardContext$value4.openPreviewPanel;
var isPreviewPanelAvailable = Boolean(openPreviewPanel && isPanelAvailable);
var isPreviewModalAvailable = Boolean(preview);
var isPreviewAvailable = isPreviewModalAvailable || isPreviewPanelAvailable;
var showPanelButtonIcon = isPreviewPanelAvailable ? 'panel' : isPreviewModalAvailable ? 'modal' : undefined;
// When inside preview panel iframe, hide the overlay button
var isInPreviewPanel = isWithinPreviewPanelIFrame();
var showPanelButton = isInPreviewPanel ? isPreviewPanelAvailable : isPreviewAvailable;
var Overlay = isPreviewAvailable ? HoverLinkOverlayWithCondition : HoverLinkOverlayNoop;
return jsx(Overlay, {
isVisible: isResolvedViewRendered,
url: url,
compactPadding: rendererAppearance === 'comment',
showPanelButton: showPanelButton,
showPanelButtonIcon: showPanelButtonIcon
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
onClick: function onClick(event) {
if (isPreviewPanelAvailable) {
var _extractSmartLinkEmbe;
// Prevent anchor default behaviour(click to open the anchor link)
// When glance panel is available, let openPreviewPanel handle it
event.preventDefault();
openPreviewPanel === null || openPreviewPanel === void 0 || openPreviewPanel({
url: resolvedUrl || '',
ari: ari || '',
name: name || '',
iconUrl: iconUrl,
panelData: {
embedUrl: expValEquals('platform_hover_card_preview_panel', 'cohort', 'test') ? (_extractSmartLinkEmbe = extractSmartLinkEmbed(cardState === null || cardState === void 0 ? void 0 : cardState.details)) === null || _extractSmartLinkEmbe === void 0 ? void 0 : _extractSmartLinkEmbe.src : undefined
}
});
editorExperiment('platform_editor_preview_panel_linking_exp', true, {
exposure: true
}) && fireHoverLabelAEP('panel');
} else if (isPreviewModalAvailable) {
event.preventDefault();
if (preview) {
preview.invoke();
}
editorExperiment('platform_editor_preview_panel_linking_exp', true, {
exposure: true
}) && fireHoverLabelAEP('modal');
}
}
}, children);
};
var InlineCard = function InlineCard(props) {
var _cardContext$value5;
var url = props.url,
data = props.data,
eventHandlers = props.eventHandlers,
fireAnalyticsEvent = props.fireAnalyticsEvent,
smartLinks = props.smartLinks,
rendererAppearance = props.rendererAppearance,
onSetLinkTarget = props.onSetLinkTarget;
var portal = usePortal(props);
var cardContext = useSmartCardContext();
var provider = useProvider('cardProvider');
var SuspenseWrapperForUrl = smartLinks === null || smartLinks === void 0 ? void 0 : smartLinks.SuspenseWrapperForUrl;
// Helper fn to conditionally wrap cards when suspense boundary is passed in via product
var wrapWithSuspense = function wrapWithSuspense(card) {
if (SuspenseWrapperForUrl && url) {
return jsx(SuspenseWrapperForUrl, {
url: url
}, card);
}
return card;
};
var _ref2 = (cardContext === null || cardContext === void 0 || (_cardContext$value5 = cardContext.value) === null || _cardContext$value5 === void 0 ? void 0 : _cardContext$value5.store) || {},
getSmartlinkState = _ref2.getState;
var _useState = useState(false),
_useState2 = _slicedToArray(_useState, 2),
isResolvedViewRendered = _useState2[0],
setIsResolvedViewRendered = _useState2[1];
var cardState = getSmartlinkState === null || getSmartlinkState === void 0 ? void 0 : getSmartlinkState()[url || ''];
var onClick = getCardClickHandler(eventHandlers, url);
var cardProps = {
url: url,
data: data,
onClick: onClick,
container: portal
};
var _ref3 = smartLinks || {},
hideHoverPreview = _ref3.hideHoverPreview,
actionOptions = _ref3.actionOptions,
ssr = _ref3.ssr,
getResolvingPlaceholder = _ref3.getResolvingPlaceholder;
var resolvingPlaceholder = url && getResolvingPlaceholder ? getResolvingPlaceholder(url) : undefined;
var analyticsData = {
attributes: {
location: 'renderer'
},
// Below is added for the future implementation of Linking Platform namespaced analytic context
location: 'renderer'
};
var inlineAnnotationProps = useInlineAnnotationProps(props);
var CompetitorPrompt = smartLinks === null || smartLinks === void 0 ? void 0 : smartLinks.CompetitorPrompt;
var CompetitorPromptComponent = CompetitorPrompt && url ? jsx(CompetitorPrompt, {
sourceUrl: url,
linkType: "inline"
}) : null;
var onError = function onError(_ref4) {
var err = _ref4.err;
if (err) {
throw err;
}
};
useEffect(function () {
if (expValEquals('platform_editor_smartlink_local_cache', 'isEnabled', true) && url) {
// Refresh cache in the background
provider === null || provider === void 0 || provider.then(function (providerInstance) {
var _refreshCache, _ref5;
(_refreshCache = (_ref5 = providerInstance).refreshCache) === null || _refreshCache === void 0 || _refreshCache.call(_ref5, {
// It's ok to cast any resourceUrl to inlineCard here, because only URL is important for the request.
type: 'inlineCard',
attrs: {
url: url
}
});
});
}
}, [provider, url]);
var MaybeOverlay = cardContext !== null && cardContext !== void 0 && cardContext.value ? OverlayWithCardContext : HoverLinkOverlayNoop;
if ((ssr || cardState && expValEquals('platform_editor_smartlink_local_cache', 'isEnabled', true)) && url && !editorExperiment('platform_editor_preview_panel_linking_exp', true, {
exposure: true
})) {
if (
// eslint-disable-next-line @atlaskit/platform/no-invalid-feature-flag-usage
fg('editor_inline_comments_on_inline_nodes')) {
return jsx(SmartLinkDraggable, {
url: url,
appearance: SMART_LINK_APPEARANCE.INLINE,
source: SMART_LINK_DRAG_TYPES.RENDERER
}, jsx("span", _extends({
"data-inline-card": true
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-computations-in-render -- Ignored via go/ees017 (to be fixed)
,
"data-card-data": data ? JSON.stringify(data) : undefined,
"data-card-url": url
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
}, inlineAnnotationProps), jsx(AnalyticsContext, {
data: analyticsData
}, wrapWithSuspense(jsx(CardSSR, {
appearance: "inline",
url: url,
showHoverPreview: !hideHoverPreview,
actionOptions: actionOptions,
onClick: onClick,
resolvingPlaceholder: resolvingPlaceholder
})))));
}
return jsx(SmartLinkDraggable, {
url: url,
appearance: SMART_LINK_APPEARANCE.INLINE,
source: SMART_LINK_DRAG_TYPES.RENDERER
}, jsx(AnalyticsContext, {
data: analyticsData
}, wrapWithSuspense(jsx(CardSSR, {
appearance: "inline",
url: url,
showHoverPreview: !hideHoverPreview,
actionOptions: actionOptions,
onClick: onClick,
resolvingPlaceholder: resolvingPlaceholder
})), CompetitorPromptComponent));
} else if ((ssr || cardState && expValEquals('platform_editor_smartlink_local_cache', 'isEnabled', true)) && url && editorExperiment('platform_editor_preview_panel_linking_exp', true, {
exposure: true
})) {
if (
// eslint-disable-next-line @atlaskit/platform/no-invalid-feature-flag-usage
fg('editor_inline_comments_on_inline_nodes')) {
return jsx(SmartLinkDraggable, {
url: url,
appearance: SMART_LINK_APPEARANCE.INLINE,
source: SMART_LINK_DRAG_TYPES.RENDERER
}, jsx("span", {
"data-inline-card": true
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-computations-in-render -- Ignored via go/ees017 (to be fixed)
,
"data-card-data": data ? JSON.stringify(data) : undefined,
"data-card-url": url,
"data-renderer-mark": inlineAnnotationProps['data-renderer-mark'],
"data-annotation-draft-mark": inlineAnnotationProps['data-annotation-draft-mark'],
"data-annotation-inline-node": inlineAnnotationProps['data-annotation-inline-node'],
"data-renderer-start-pos": inlineAnnotationProps['data-renderer-start-pos'],
"data-annotation-mark": inlineAnnotationProps['data-annotation-mark']
}, jsx(AnalyticsContext, {
data: analyticsData
}, jsx(MaybeOverlay, {
url: url || '',
rendererAppearance: rendererAppearance,
isResolvedViewRendered: isResolvedViewRendered,
fireAnalyticsEvent: fireAnalyticsEvent
}, wrapWithSuspense(jsx(CardSSR, {
appearance: "inline",
url: url,
showHoverPreview: !hideHoverPreview,
actionOptions: actionOptions,
onClick: onClick,
resolvingPlaceholder: resolvingPlaceholder
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
onResolve: function onResolve(data) {
if (!data.url || !data.title) {
return;
}
props.smartCardStorage.set(data.url, data.title);
if (data.title) {
setIsResolvedViewRendered(true);
}
},
onError: onError,
disablePreviewPanel: true
}))))));
}
return jsx(SmartLinkDraggable, {
url: url,
appearance: SMART_LINK_APPEARANCE.INLINE,
source: SMART_LINK_DRAG_TYPES.RENDERER
}, jsx(AnalyticsContext, {
data: analyticsData
}, jsx(MaybeOverlay, {
url: url || '',
rendererAppearance: rendererAppearance,
isResolvedViewRendered: isResolvedViewRendered,
fireAnalyticsEvent: fireAnalyticsEvent
}, wrapWithSuspense(jsx(CardSSR, {
appearance: "inline",
url: url,
showHoverPreview: !hideHoverPreview,
actionOptions: actionOptions,
onClick: onClick,
resolvingPlaceholder: resolvingPlaceholder
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
onResolve: function onResolve(data) {
if (!data.url || !data.title) {
return;
}
props.smartCardStorage.set(data.url, data.title);
if (data.title) {
setIsResolvedViewRendered(true);
}
},
onError: onError,
disablePreviewPanel: true
}))), CompetitorPromptComponent));
}
return jsx(SmartLinkDraggable, {
url: url || '',
appearance: SMART_LINK_APPEARANCE.INLINE,
source: SMART_LINK_DRAG_TYPES.RENDERER
}, jsx(AnalyticsContext, {
data: analyticsData
}, jsx("span", _extends({
"data-inline-card": true
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-computations-in-render -- Ignored via go/ees017 (to be fixed)
,
"data-card-data": data ? JSON.stringify(data) : undefined,
"data-card-url": url
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
}, inlineAnnotationProps), jsx(CardErrorBoundary, _extends({
unsupportedComponent: UnsupportedInline
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
}, cardProps, {
onSetLinkTarget: onSetLinkTarget
}), jsx(MaybeOverlay, {
url: url || '',
rendererAppearance: rendererAppearance,
isResolvedViewRendered: isResolvedViewRendered,
fireAnalyticsEvent: fireAnalyticsEvent
}, wrapWithSuspense(jsx(Card, _extends({
appearance: "inline",
showHoverPreview: !hideHoverPreview,
actionOptions: actionOptions,
resolvingPlaceholder: resolvingPlaceholder
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
}, cardProps, {
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
onResolve: function onResolve(data) {
if (!data.url || !data.title) {
return;
}
props.smartCardStorage.set(data.url, data.title);
if (data.title) {
setIsResolvedViewRendered(true);
}
},
onError: onError,
disablePreviewPanel: editorExperiment('platform_editor_preview_panel_linking_exp', true, {
exposure: true
})
})))), CompetitorPromptComponent))));
};
var _default_1 = withSmartCardStorage(InlineCard);
export default _default_1;