@atlaskit/editor-core
Version:
A package contains Atlassian editor core functionality
85 lines (83 loc) • 4.06 kB
JavaScript
import { useCallback, useEffect, useRef } from 'react';
import { ACTION, ACTION_SUBJECT, EVENT_TYPE, getAnalyticsEventsFromTransaction } from '@atlaskit/editor-common/analytics';
import { isDirtyTransaction } from '@atlaskit/editor-common/collab';
import { getDocStructure } from '@atlaskit/editor-common/core-utils';
import { startMeasure, stopMeasure } from '@atlaskit/editor-common/performance-measures';
import { findChangedNodesFromTransaction } from '../../utils/findChangedNodesFromTransaction';
import { freezeUnsafeTransactionProperties } from '../../utils/performance/safer-transactions';
import { EVENT_NAME_ON_CHANGE } from '../../utils/performance/track-transactions';
import { validateNodes, validNode } from '../../utils/validateNodes';
export var useDispatchTransaction = function useDispatchTransaction(_ref) {
var onChange = _ref.onChange,
dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent,
onEditorViewUpdated = _ref.onEditorViewUpdated,
isRemoteReplaceDocumentTransaction = _ref.isRemoteReplaceDocumentTransaction;
// We need to have a ref to the latest `onChange` since the `dispatchTransaction` gets captured
var onChangeRef = useRef(onChange);
useEffect(function () {
onChangeRef.current = onChange;
}, [onChange]);
var dispatchTransaction = useCallback(function (view, unsafeTransaction) {
if (!view) {
return;
}
var nodes = findChangedNodesFromTransaction(unsafeTransaction);
var changedNodesValid = validateNodes(nodes);
var transaction = new Proxy(unsafeTransaction, freezeUnsafeTransactionProperties({
dispatchAnalyticsEvent: dispatchAnalyticsEvent,
pluginKey: 'unknown-reacteditorview'
}));
// If the transaction is a remote replaceDocument transaction, we should skip validation.
// Remote replaceDocument transactions are fired when the document is replaced by initialization of editor-plugin-collab-edit
// If there is a discrepancy in the ProseMirror schema at initialization, it results in the editor being loaded with no content,
// giving the user the impression that content has been lost
var isRemoteReplace = isRemoteReplaceDocumentTransaction ? isRemoteReplaceDocumentTransaction(transaction) : false;
if (changedNodesValid || isRemoteReplace) {
var oldEditorState = view.state;
// go ahead and update the state now we know the transaction is good
var _view$state$applyTran = view.state.applyTransaction(transaction),
newEditorState = _view$state$applyTran.state,
transactions = _view$state$applyTran.transactions;
if (newEditorState === oldEditorState) {
return;
}
view.updateState(newEditorState);
onEditorViewUpdated({
originalTransaction: transaction,
transactions: transactions,
oldEditorState: oldEditorState,
newEditorState: newEditorState
});
if (onChangeRef.current && transaction.docChanged) {
var source = transaction.getMeta('isRemote') ? 'remote' : 'local';
var isDirtyChange = isDirtyTransaction(transaction);
startMeasure(EVENT_NAME_ON_CHANGE);
onChangeRef.current(view, {
source: source,
isDirtyChange: isDirtyChange
});
stopMeasure(EVENT_NAME_ON_CHANGE);
}
}
if (!changedNodesValid) {
var invalidNodes = nodes.filter(function (node) {
return !validNode(node);
}).map(function (node) {
return getDocStructure(node, {
compact: true
});
});
dispatchAnalyticsEvent({
action: ACTION.DISPATCHED_INVALID_TRANSACTION,
actionSubject: ACTION_SUBJECT.EDITOR,
eventType: EVENT_TYPE.OPERATIONAL,
attributes: {
analyticsEventPayloads: getAnalyticsEventsFromTransaction(transaction),
invalidNodes: invalidNodes,
isRemoteReplaceDocumentTransaction: isRemoteReplace
}
});
}
}, [dispatchAnalyticsEvent, onEditorViewUpdated, isRemoteReplaceDocumentTransaction]);
return dispatchTransaction;
};