UNPKG

@atlaskit/editor-plugin-date

Version:

Date plugin for @atlaskit/editor-core

303 lines (301 loc) 13 kB
import React from 'react'; import Loadable from 'react-loadable'; import { date, dateWithLocalId } from '@atlaskit/adf-schema'; import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics'; import { useSharedPluginState } from '@atlaskit/editor-common/hooks'; import { ToolTipContent } from '@atlaskit/editor-common/keymaps'; import { annotationMessages, toolbarInsertBlockMessages as messages } from '@atlaskit/editor-common/messages'; import { IconDate } from '@atlaskit/editor-common/quick-insert'; import { DateSharedCssClassName } from '@atlaskit/editor-common/styles'; import { calculateToolbarPositionAboveSelection } from '@atlaskit/editor-common/utils'; import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils'; import CommentIcon from '@atlaskit/icon/core/comment'; import { fg } from '@atlaskit/platform-feature-flags'; import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals'; import { closeDatePicker, closeDatePickerWithAnalytics, createDate } from './pm-plugins/actions'; import { deleteDateCommand, insertDateCommand } from './pm-plugins/commands'; import keymap from './pm-plugins/keymap'; import createDatePlugin from './pm-plugins/main'; import { pluginKey as datePluginKey } from './pm-plugins/plugin-key'; const DatePicker = Loadable({ loader: () => import( /* webpackChunkName: "@atlaskit-internal_editor-datepicker" */'./ui/DatePicker').then(mod => mod.default), loading: () => null }); function getDateNode(editorView, showDatePickerAt) { if (!editorView) { return null; } const domAtPos = editorView.domAtPos.bind(editorView); // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting const element = findDomRefAtPos(showDatePickerAt, domAtPos); // Resolves ED-23702 for when the date is wrapped in an inline comment const dateNode = element !== null && element !== void 0 && element.classList.contains(DateSharedCssClassName.DATE_CONTAINER) ? element : element === null || element === void 0 ? void 0 : element.querySelector(`.${DateSharedCssClassName.DATE_CONTAINER}`); return dateNode || element; } function ContentComponent({ editorView, dispatchAnalyticsEvent, popupsMountPoint, popupsBoundariesElement, popupsScrollableElement, dependencyApi, weekStartDay }) { const { editorDisabledState, dateState } = useSharedPluginState(dependencyApi, ['date', 'editorDisabled']); if (!(dateState !== null && dateState !== void 0 && dateState.showDatePickerAt) || editorDisabledState !== null && editorDisabledState !== void 0 && editorDisabledState.editorDisabled) { return null; } const { showDatePickerAt, isNew, focusDateInput } = dateState; const dateNode = getDateNode(editorView, showDatePickerAt); return /*#__PURE__*/React.createElement(DatePicker, { mountTo: popupsMountPoint, boundariesElement: popupsBoundariesElement, scrollableElement: popupsScrollableElement, key: showDatePickerAt, element: dateNode, isNew: isNew, autoFocus: focusDateInput // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onDelete: () => { var _dependencyApi$core; if (expValEquals('platform_editor_hydratable_ui', 'isEnabled', true) && !editorView) { return; } dependencyApi === null || dependencyApi === void 0 ? void 0 : (_dependencyApi$core = dependencyApi.core) === null || _dependencyApi$core === void 0 ? void 0 : _dependencyApi$core.actions.execute(deleteDateCommand(dependencyApi)); editorView === null || editorView === void 0 ? void 0 : editorView.focus(); } // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onSelect: (date, commitMethod) => { var _dependencyApi$core2; // Undefined means couldn't parse date, null means invalid (out of bounds) date if (date === undefined || date === null) { return; } if (expValEquals('platform_editor_hydratable_ui', 'isEnabled', true) && !editorView) { return; } dependencyApi === null || dependencyApi === void 0 ? void 0 : (_dependencyApi$core2 = dependencyApi.core) === null || _dependencyApi$core2 === void 0 ? void 0 : _dependencyApi$core2.actions.execute(insertDateCommand(dependencyApi)({ date, commitMethod })); editorView === null || editorView === void 0 ? void 0 : editorView.focus(); } // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onTextChanged: date => { var _dependencyApi$core3; dependencyApi === null || dependencyApi === void 0 ? void 0 : (_dependencyApi$core3 = dependencyApi.core) === null || _dependencyApi$core3 === void 0 ? void 0 : _dependencyApi$core3.actions.execute(insertDateCommand(dependencyApi)({ date, enterPressed: false })); } // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , closeDatePicker: () => { if (!editorView) { return; } closeDatePicker()(editorView.state, editorView.dispatch); editorView === null || editorView === void 0 ? void 0 : editorView.focus(); } // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , closeDatePickerWithAnalytics: ({ date }) => { if (!editorView) { return; } closeDatePickerWithAnalytics({ date })(editorView.state, editorView.dispatch); editorView.focus(); }, dispatchAnalyticsEvent: dispatchAnalyticsEvent, weekStartDay: weekStartDay }); } const datePlugin = ({ config = {}, api }) => ({ name: 'date', getSharedState(editorState) { if (!editorState) { return { showDatePickerAt: null, isNew: false, focusDateInput: false, isInitialised: true }; } const { showDatePickerAt, isNew, focusDateInput, isInitialised } = datePluginKey.getState(editorState) || {}; return { showDatePickerAt, isNew: !!isNew, focusDateInput: !!focusDateInput, isInitialised: !!isInitialised }; }, commands: { insertDate: insertDateCommand(api), deleteDate: deleteDateCommand(api) }, nodes() { return [{ name: 'date', node: fg('platform_editor_adf_with_localid') ? dateWithLocalId : date }]; }, pmPlugins() { return [{ name: 'date', plugin: pmPluginFactoryParams => { DatePicker.preload(); return createDatePlugin(pmPluginFactoryParams); } }, { name: 'dateKeymap', plugin: () => { DatePicker.preload(); return keymap(); } }]; }, contentComponent({ editorView, dispatchAnalyticsEvent, popupsMountPoint, popupsBoundariesElement, popupsScrollableElement }) { if (!editorView) { return null; } return /*#__PURE__*/React.createElement(ContentComponent, { dependencyApi: api, editorView: editorView, dispatchAnalyticsEvent: dispatchAnalyticsEvent, popupsMountPoint: popupsMountPoint, popupsBoundariesElement: popupsBoundariesElement, popupsScrollableElement: popupsScrollableElement, weekStartDay: config.weekStartDay }); }, pluginsOptions: { quickInsert: ({ formatMessage }) => [{ id: 'date', title: formatMessage(messages.date), description: formatMessage(messages.dateDescription), priority: 800, keywords: ['calendar', 'day', 'time', 'today', '/'], keyshortcut: '//', icon: () => /*#__PURE__*/React.createElement(IconDate, null), action(insert, state, source) { var _api$analytics, _api$analytics$action, _api$analytics$action2; const tr = createDate(true)(state); api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : (_api$analytics$action = _api$analytics.actions) === null || _api$analytics$action === void 0 ? void 0 : (_api$analytics$action2 = _api$analytics$action.attachAnalyticsEvent) === null || _api$analytics$action2 === void 0 ? void 0 : _api$analytics$action2.call(_api$analytics$action, { action: ACTION.INSERTED, actionSubject: ACTION_SUBJECT.DOCUMENT, actionSubjectId: ACTION_SUBJECT_ID.DATE, eventType: EVENT_TYPE.TRACK, attributes: { inputMethod: source !== null && source !== void 0 ? source : INPUT_METHOD.QUICK_INSERT } })(tr); return tr; } }], floatingToolbar: (state, intl) => { const isViewMode = () => { var _api$editorViewMode, _api$editorViewMode$s; return (api === null || api === void 0 ? void 0 : (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 ? void 0 : (_api$editorViewMode$s = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode$s === void 0 ? void 0 : _api$editorViewMode$s.mode) === 'view'; }; if (!isViewMode()) { return undefined; } const onClick = (stateFromClickEvent, dispatch) => { var _api$analytics2, _api$annotation, _api$annotation$actio; if (!(api !== null && api !== void 0 && api.annotation)) { return true; } if (api !== null && api !== void 0 && (_api$analytics2 = api.analytics) !== null && _api$analytics2 !== void 0 && _api$analytics2.actions) { var _api$analytics3, _api$analytics3$actio; api === null || api === void 0 ? void 0 : (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : (_api$analytics3$actio = _api$analytics3.actions) === null || _api$analytics3$actio === void 0 ? void 0 : _api$analytics3$actio.fireAnalyticsEvent({ action: ACTION.CLICKED, actionSubject: ACTION_SUBJECT.BUTTON, actionSubjectId: ACTION_SUBJECT_ID.CREATE_INLINE_COMMENT_FROM_HIGHLIGHT_ACTIONS_MENU, eventType: EVENT_TYPE.UI, attributes: { source: 'highlightActionsMenu', pageMode: 'edit', sourceNode: 'date' } }); } const command = (_api$annotation = api.annotation) === null || _api$annotation === void 0 ? void 0 : (_api$annotation$actio = _api$annotation.actions) === null || _api$annotation$actio === void 0 ? void 0 : _api$annotation$actio.setInlineCommentDraftState(true, INPUT_METHOD.TOOLBAR); return command(stateFromClickEvent, dispatch); }; return { title: 'Date floating toolbar', nodeType: [state.schema.nodes.date], getDomRef: editorView => { const dateState = datePluginKey.getState(state); const datePosition = dateState === null || dateState === void 0 ? void 0 : dateState.showDatePickerAt; if (!datePosition) { return undefined; } const domAtPos = editorView.domAtPos.bind(editorView); const domRef = findDomRefAtPos(datePosition, domAtPos); const isHTMLElement = element => { return element instanceof HTMLElement; }; if (isHTMLElement(domRef)) { return domRef; } return undefined; }, onPositionCalculated: calculateToolbarPositionAboveSelection('Date floating toolbar'), items: node => { var _api$annotation2; const annotationState = api === null || api === void 0 ? void 0 : (_api$annotation2 = api.annotation) === null || _api$annotation2 === void 0 ? void 0 : _api$annotation2.sharedState.currentState(); const activeCommentMark = node.marks.find(mark => mark.type.name === 'annotation' && (annotationState === null || annotationState === void 0 ? void 0 : annotationState.annotations[mark.attrs.id]) === false); const showAnnotation = annotationState && annotationState.isVisible && isViewMode() && !annotationState.bookmark && !annotationState.mouseData.isSelecting && !activeCommentMark; if (showAnnotation) { return [{ type: 'button', showTitle: true, testId: 'add-comment-date-button', icon: CommentIcon, title: intl.formatMessage(annotationMessages.createComment), onClick, tooltipContent: /*#__PURE__*/React.createElement(ToolTipContent, { description: intl.formatMessage(annotationMessages.createComment) }), supportsViewMode: true }]; } return []; } }; } } }); export default datePlugin;