@atlaskit/editor-plugin-card
Version:
Card plugin for @atlaskit/editor-core
191 lines (189 loc) • 6.96 kB
JavaScript
import React from 'react';
import { ACTION, buildEditLinkPayload, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
import { commandWithMetadata } from '@atlaskit/editor-common/card';
import { HyperlinkAddToolbar as HyperlinkToolbar } from '@atlaskit/editor-common/link';
import { linkToolbarMessages } from '@atlaskit/editor-common/messages';
import { LINKPICKER_HEIGHT_IN_PX, RECENT_SEARCH_HEIGHT_IN_PX, RECENT_SEARCH_WIDTH_IN_PX } from '@atlaskit/editor-common/ui';
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
import { hideLinkToolbar, showLinkToolbar } from '../pm-plugins/actions';
import { changeSelectedCardToLink, updateCard } from '../pm-plugins/doc';
import { displayInfoForCard, findCardInfo } from '../pm-plugins/utils';
export function HyperlinkAddToolbarWithState({
linkPickerOptions = {},
onSubmit,
displayText,
displayUrl,
providerFactory,
view,
onCancel,
invokeMethod,
lpLinkPicker,
onClose,
onEscapeCallback,
onClickAwayCallback
}) {
return /*#__PURE__*/React.createElement(HyperlinkToolbar, {
linkPickerOptions: linkPickerOptions,
onSubmit: onSubmit,
displayText: displayText,
displayUrl: displayUrl,
providerFactory: providerFactory,
view: view,
onCancel: onCancel,
invokeMethod: invokeMethod,
lpLinkPicker: lpLinkPicker,
onClose: onClose,
onEscapeCallback: onEscapeCallback,
onClickAwayCallback: onClickAwayCallback
});
}
// eslint-disable-next-line @repo/internal/react/no-class-components
export class EditLinkToolbar extends React.Component {
componentDidUpdate(prevProps) {
if (prevProps.node !== this.props.node) {
this.hideLinkToolbar();
}
}
componentWillUnmount() {
this.hideLinkToolbar();
}
hideLinkToolbar() {
const {
view
} = this.props;
view.dispatch(hideLinkToolbar(view.state.tr));
}
render() {
const {
linkPickerOptions,
providerFactory,
url,
text,
view,
onSubmit,
forceFocusSelector,
lpLinkPicker
} = this.props;
return /*#__PURE__*/React.createElement(HyperlinkAddToolbarWithState, {
view: view,
linkPickerOptions: linkPickerOptions,
providerFactory: providerFactory,
displayUrl: url,
displayText: text
// Assumes that the smart card link picker can only ever be invoked by clicking "edit"
// via the floating toolbar
,
invokeMethod: INPUT_METHOD.FLOATING_TB,
lpLinkPicker: lpLinkPicker
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
onSubmit: (href, title, displayText, inputMethod, analytic) => {
this.hideLinkToolbar();
if (onSubmit) {
onSubmit(href, displayText || title, inputMethod, analytic);
}
}
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
onEscapeCallback: (state, dispatch) => {
const {
tr
} = state;
hideLinkToolbar(tr);
forceFocusSelector === null || forceFocusSelector === void 0 ? void 0 : forceFocusSelector(`[aria-label="${linkToolbarMessages.editLink.defaultMessage}"]`)(tr);
if (dispatch) {
dispatch(tr);
return true;
}
return false;
}
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
onClickAwayCallback: (state, dispatch) => {
const {
tr
} = state;
if (dispatch) {
dispatch(tr);
return true;
}
return false;
}
});
}
}
export const getEditLinkCallback = (editorAnalyticsApi, scrollIntoView) => (state, dispatch) => {
let type = 'hyperlink';
if (state.selection instanceof NodeSelection) {
type = state.selection.node.type.name;
}
if (dispatch) {
const {
tr
} = state;
showLinkToolbar(tr);
editorAnalyticsApi === null || editorAnalyticsApi === void 0 ? void 0 : editorAnalyticsApi.attachAnalyticsEvent(buildEditLinkPayload(type))(tr);
tr.setMeta('scrollIntoView', scrollIntoView);
dispatch(tr);
return true;
}
return false;
};
export const buildEditLinkToolbar = ({
providerFactory,
node,
pluginInjectionApi,
linkPicker,
lpLinkPicker
}) => {
return {
type: 'custom',
disableArrowNavigation: true,
fallback: [],
render: (view, idx) => {
var _pluginInjectionApi$f, _pluginInjectionApi$f2;
if (!view || !providerFactory) {
return null;
}
const displayInfo = displayInfoForCard(node, findCardInfo(view.state));
return /*#__PURE__*/React.createElement(EditLinkToolbar, {
key: idx,
view: view,
linkPickerOptions: linkPicker,
providerFactory: providerFactory,
url: displayInfo.url,
text: displayInfo.title || '',
node: node,
lpLinkPicker: lpLinkPicker,
forceFocusSelector: pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$f = pluginInjectionApi.floatingToolbar) === null || _pluginInjectionApi$f === void 0 ? void 0 : (_pluginInjectionApi$f2 = _pluginInjectionApi$f.actions) === null || _pluginInjectionApi$f2 === void 0 ? void 0 : _pluginInjectionApi$f2.forceFocusSelector
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
onSubmit: (newHref, newText, inputMethod, analytic) => {
const urlChanged = newHref !== displayInfo.url;
const titleChanged = newText !== displayInfo.title;
// If the title is changed in a smartlink, convert to standard blue hyperlink
// (even if the url was also changed) - we don't want to lose the custom title.
if (titleChanged) {
var _pluginInjectionApi$a;
return commandWithMetadata(changeSelectedCardToLink(newText, newHref, undefined, undefined, undefined, pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a === void 0 ? void 0 : _pluginInjectionApi$a.actions), {
action: ACTION.UPDATED,
inputMethod,
sourceEvent: analytic
})(view.state, view.dispatch);
}
if (urlChanged) {
// If *only* the url is changed in a smart link, reresolve
return updateCard(newHref, analytic)(view.state, view.dispatch);
}
}
});
}
};
};
export const editLinkToolbarConfig = (showLinkingToolbar, lpLinkPicker) => {
return showLinkingToolbar ? {
height: lpLinkPicker ? LINKPICKER_HEIGHT_IN_PX : RECENT_SEARCH_HEIGHT_IN_PX,
width: RECENT_SEARCH_WIDTH_IN_PX,
forcePlacement: true
} : {};
};