@atlaskit/editor-plugin-card
Version:
Card plugin for @atlaskit/editor-core
169 lines (165 loc) • 6.32 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import React, { useCallback } from 'react';
import { isSafeUrl } from '@atlaskit/adf-schema';
import { AnalyticsContext } from '@atlaskit/analytics-next';
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
import { getAnalyticsEditorAppearance } from '@atlaskit/editor-common/utils';
import Link from '@atlaskit/link';
import { fg } from '@atlaskit/platform-feature-flags';
import { changeSelectedCardToLinkFallback } from '../pm-plugins/doc';
import { getPluginState } from '../pm-plugins/util/state';
import { titleUrlPairFromNode } from '../pm-plugins/utils';
import { WithCardContext } from '../ui/WithCardContext';
const fatalErrorPositionMap = new Map();
const WithClickHandler = ({
pluginInjectionApi,
url,
onClickCallback,
children
}) => {
const {
mode
} = useSharedPluginStateWithSelector(pluginInjectionApi, ['editorViewMode'], states => {
var _states$editorViewMod;
return {
mode: (_states$editorViewMod = states.editorViewModeState) === null || _states$editorViewMod === void 0 ? void 0 : _states$editorViewMod.mode
};
});
const onClick = useCallback(event => {
if (typeof onClickCallback === 'function') {
try {
onClickCallback({
event,
url
});
} catch {}
}
}, [url, onClickCallback]);
// Setting `onClick` to `undefined` ensures clicks on smartcards navigate to the URL.
// If in view mode and not overriding with onClickCallback option, then allow smartlinks to navigate on click.
const allowNavigation = mode === 'view' && !onClickCallback;
return /*#__PURE__*/React.createElement(React.Fragment, null, children({
onClick: allowNavigation ? undefined : onClick
}));
};
/**
*
* @param SmartCardComponent
* @param UnsupportedComponent
* @example
*/
export function Card(SmartCardComponent, UnsupportedComponent) {
return class extends React.Component {
constructor(...args) {
super(...args);
_defineProperty(this, "state", {
isError: false
});
}
render() {
var _getPluginState;
const {
pluginInjectionApi,
onClickCallback
} = this.props;
const {
url
} = titleUrlPairFromNode(this.props.node);
if (url && !isSafeUrl(url)) {
return /*#__PURE__*/React.createElement(UnsupportedComponent, null);
}
if (this.state.isError) {
if (url) {
return fg('dst-a11y__replace-anchor-with-link__linking-platfo') ? /*#__PURE__*/React.createElement(Link, {
href: url
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
onClick: e => {
e.preventDefault();
}
}, url) :
/*#__PURE__*/
// eslint-disable-next-line @atlaskit/design-system/no-html-anchor
React.createElement("a", {
href: url,
onClick: e => {
e.preventDefault();
}
}, url);
} else {
return /*#__PURE__*/React.createElement(UnsupportedComponent, null);
}
}
const editorAppearance = (_getPluginState = getPluginState(this.props.view.state)) === null || _getPluginState === void 0 ? void 0 : _getPluginState.editorAppearance;
const analyticsEditorAppearance = getAnalyticsEditorAppearance(editorAppearance);
return /*#__PURE__*/React.createElement(AnalyticsContext
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
, {
data: {
attributes: {
location: analyticsEditorAppearance
},
// Below is added for the future implementation of Linking Platform namespaced analytics context
location: analyticsEditorAppearance
}
}, /*#__PURE__*/React.createElement(WithClickHandler, {
pluginInjectionApi: pluginInjectionApi,
onClickCallback: onClickCallback,
url: url
}, ({
onClick
}) => /*#__PURE__*/React.createElement(WithCardContext, null, cardContext => /*#__PURE__*/React.createElement(SmartCardComponent, _extends({
key: url,
cardContext: cardContext
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
}, this.props, {
onClick: onClick
})))));
}
componentDidCatch(error) {
const maybeAPIError = error;
// NB: errors received in this component are propagated by the `@atlaskit/smart-card` component.
// Depending on the kind of error, the expectation for this component is to either:
// (1) Render a blue link whilst retaining `inlineCard` in the ADF (non-fatal errs);
// (2) Render a blue link whilst downgrading to `link` in the ADF (fatal errs).
if (maybeAPIError.kind && maybeAPIError.kind === 'fatal') {
var _pluginInjectionApi$a;
this.setState({
isError: true
});
const {
view,
node,
getPos,
pluginInjectionApi
} = this.props;
const {
url
} = titleUrlPairFromNode(node);
if (!getPos || typeof getPos === 'boolean') {
return;
}
const pos = getPos();
/**
* We cache fatal errors by position to avoid retrying the same errors
* on the same links at the same position.
*/
if (url && pos && fatalErrorPositionMap.get(url) === pos) {
return null;
}
changeSelectedCardToLinkFallback(undefined, url, true, node, getPos(), pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a === void 0 ? void 0 : _pluginInjectionApi$a.actions)(view.state, view.dispatch);
if (url && pos) {
fatalErrorPositionMap.set(url, pos);
}
return null;
} else {
// Otherwise, render a blue link as fallback (above in render()).
this.setState({
isError: true
});
}
}
};
}