UNPKG

@atlaskit/editor-plugin-card

Version:

Card plugin for @atlaskit/editor-core

169 lines (165 loc) 6.32 kB
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 }); } } }; }