@atlaskit/editor-plugin-track-changes 1.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @atlaskit/editor-plugin-track-changes
2
2
 
3
+ ## 2.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#189258](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/189258)
8
+ [`e6411aa283a9e`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/e6411aa283a9e) -
9
+ Exposes new state to track if the diff plugin is available for use (ie. for external buttons).
10
+ Defaults to false and is set to true when changes are available.
11
+
12
+ ## 2.0.0
13
+
14
+ ### Major Changes
15
+
16
+ - [#185139](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/185139)
17
+ [`710f9b65a743a`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/710f9b65a743a) -
18
+ [EDITOR-1014] Setup basic plugin diffing functionality and documentation
19
+
3
20
  ## 1.0.0
4
21
 
5
22
  ### Major Changes
@@ -0,0 +1,27 @@
1
+ {
2
+ "extends": "../../../../tsconfig.entry-points.confluence.json",
3
+ "compilerOptions": {
4
+ "target": "es5",
5
+ "composite": true,
6
+ "outDir": "../../../../../confluence/tsDist/@atlaskit__editor-plugin-track-changes",
7
+ "rootDir": "../"
8
+ },
9
+ "include": [
10
+ "../src/**/*.ts",
11
+ "../src/**/*.tsx"
12
+ ],
13
+ "exclude": [
14
+ "../src/**/__tests__/*",
15
+ "../src/**/*.test.*",
16
+ "../src/**/test.*",
17
+ "../src/**/examples.*"
18
+ ],
19
+ "references": [
20
+ {
21
+ "path": "../../../design-system/tokens/afm-cc/tsconfig.json"
22
+ },
23
+ {
24
+ "path": "../../editor-common/afm-cc/tsconfig.json"
25
+ }
26
+ ]
27
+ }
@@ -0,0 +1,66 @@
1
+ {
2
+ "extends": "../../../../tsconfig.entry-points.jira.json",
3
+ "compilerOptions": {
4
+ "target": "es5",
5
+ "outDir": "../../../../../tsDist/@atlaskit__editor-plugin-toolbar-lists-indentation/app",
6
+ "rootDir": "../",
7
+ "composite": true
8
+ },
9
+ "include": [
10
+ "../src/**/*.ts",
11
+ "../src/**/*.tsx"
12
+ ],
13
+ "exclude": [
14
+ "../src/**/__tests__/*",
15
+ "../src/**/*.test.*",
16
+ "../src/**/test.*",
17
+ "../src/**/examples.*"
18
+ ],
19
+ "references": [
20
+ {
21
+ "path": "../../../design-system/css/afm-jira/tsconfig.json"
22
+ },
23
+ {
24
+ "path": "../../editor-plugin-analytics/afm-jira/tsconfig.json"
25
+ },
26
+ {
27
+ "path": "../../editor-plugin-block-type/afm-jira/tsconfig.json"
28
+ },
29
+ {
30
+ "path": "../../editor-plugin-feature-flags/afm-jira/tsconfig.json"
31
+ },
32
+ {
33
+ "path": "../../editor-plugin-indentation/afm-jira/tsconfig.json"
34
+ },
35
+ {
36
+ "path": "../../editor-plugin-list/afm-jira/tsconfig.json"
37
+ },
38
+ {
39
+ "path": "../../editor-plugin-primary-toolbar/afm-jira/tsconfig.json"
40
+ },
41
+ {
42
+ "path": "../../editor-plugin-selection-toolbar/afm-jira/tsconfig.json"
43
+ },
44
+ {
45
+ "path": "../../editor-plugin-tasks-and-decisions/afm-jira/tsconfig.json"
46
+ },
47
+ {
48
+ "path": "../../editor-shared-styles/afm-jira/tsconfig.json"
49
+ },
50
+ {
51
+ "path": "../../../design-system/icon/afm-jira/tsconfig.json"
52
+ },
53
+ {
54
+ "path": "../../../platform/feature-flags/afm-jira/tsconfig.json"
55
+ },
56
+ {
57
+ "path": "../../tmp-editor-statsig/afm-jira/tsconfig.json"
58
+ },
59
+ {
60
+ "path": "../../../design-system/tokens/afm-jira/tsconfig.json"
61
+ },
62
+ {
63
+ "path": "../../editor-common/afm-jira/tsconfig.json"
64
+ }
65
+ ]
66
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "extends": "../../../../tsconfig.entry-points.post-office.json",
3
+ "compilerOptions": {
4
+ "target": "es5",
5
+ "outDir": "../../../../../post-office/tsDist/@atlaskit__editor-plugin-toolbar-lists-indentation/app",
6
+ "rootDir": "../",
7
+ "composite": true
8
+ },
9
+ "include": [
10
+ "../src/**/*.ts",
11
+ "../src/**/*.tsx"
12
+ ],
13
+ "exclude": [
14
+ "../src/**/__tests__/*",
15
+ "../src/**/*.test.*",
16
+ "../src/**/test.*",
17
+ "../src/**/examples.*"
18
+ ],
19
+ "references": [
20
+ {
21
+ "path": "../editor-common/tsconfig.app.json"
22
+ },
23
+ {
24
+ "path": "../../design-system/tokens/tsconfig.app.json"
25
+ }
26
+ ]
27
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "extends": "../../../../tsconfig.entry-points.volt.json",
3
+ "compilerOptions": {
4
+ "target": "es5",
5
+ "outDir": "../../../../../volt/tsDist/@atlaskit__editor-plugin-toolbar-lists-indentation/app",
6
+ "rootDir": "../",
7
+ "composite": true
8
+ },
9
+ "include": [
10
+ "../src/**/*.ts",
11
+ "../src/**/*.tsx"
12
+ ],
13
+ "exclude": [
14
+ "../src/**/__tests__/*",
15
+ "../src/**/*.test.*",
16
+ "../src/**/test.*",
17
+ "../src/**/examples.*"
18
+ ],
19
+ "references": [
20
+ {
21
+ "path": "../editor-common/tsconfig.app.json"
22
+ },
23
+ {
24
+ "path": "../../design-system/tokens/tsconfig.app.json"
25
+ }
26
+ ]
27
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createInlineChangedDecoration = exports.createDeletedContentDecoration = void 0;
7
+ var _lazyNodeView = require("@atlaskit/editor-common/lazy-node-view");
8
+ var _model = require("@atlaskit/editor-prosemirror/model");
9
+ var _view = require("@atlaskit/editor-prosemirror/view");
10
+ var style = (0, _lazyNodeView.convertToInlineCss)({
11
+ background: "var(--ds-background-accent-purple-subtlest, #F3F0FF)",
12
+ textDecoration: 'underline',
13
+ textDecorationStyle: 'dotted',
14
+ textDecorationThickness: "var(--ds-space-025, 2px)",
15
+ textDecorationColor: "var(--ds-border-accent-purple, #8270DB)"
16
+ });
17
+
18
+ /**
19
+ * Inline decoration used for insertions as the content already exists in the document
20
+ *
21
+ * @param change Changeset "change" containing information about the change content + range
22
+ * @returns Prosemirror inline decoration
23
+ */
24
+ var createInlineChangedDecoration = exports.createInlineChangedDecoration = function createInlineChangedDecoration(change) {
25
+ return _view.Decoration.inline(change.fromB, change.toB, {
26
+ style: style
27
+ }, {});
28
+ };
29
+ var deletedContentStyle = (0, _lazyNodeView.convertToInlineCss)({
30
+ color: "var(--ds-text-accent-gray, #44546F)",
31
+ textDecoration: 'line-through'
32
+ });
33
+
34
+ /**
35
+ * Creates a widget to represent the deleted content in the editor
36
+ *
37
+ * @param props.change Changeset "change" containing information about the change content + range
38
+ * @param props.doc Baseline doc to compare against
39
+ * @param props.tr The relevant transaction this decoration is being created against
40
+ * @returns Prosemirror widget decoration
41
+ */
42
+ var createDeletedContentDecoration = exports.createDeletedContentDecoration = function createDeletedContentDecoration(_ref) {
43
+ var change = _ref.change,
44
+ doc = _ref.doc,
45
+ tr = _ref.tr;
46
+ var dom = document.createElement('span');
47
+ dom.setAttribute('style', deletedContentStyle);
48
+ dom.appendChild(_model.DOMSerializer.fromSchema(tr.doc.type.schema).serializeFragment(doc.slice(change.fromA, change.toA).content));
49
+
50
+ // Widget decoration used for deletions as the content is not in the document
51
+ // and we want to display the deleted content with a style.
52
+ return _view.Decoration.widget(change.fromB, dom, {
53
+ marks: []
54
+ });
55
+ };
@@ -1,28 +1,98 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
6
7
  exports.trackChangesPluginKey = exports.createTrackChangesPlugin = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
+ var _prosemirrorChangeset = require("prosemirror-changeset");
7
10
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
8
11
  var _state = require("@atlaskit/editor-prosemirror/state");
9
- var trackChangesPluginKey = exports.trackChangesPluginKey = new _state.PluginKey('showDiffPlugin');
10
-
11
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
12
-
12
+ var _transform = require("@atlaskit/editor-prosemirror/transform");
13
+ var _view = require("@atlaskit/editor-prosemirror/view");
14
+ var _decorations = require("./decorations");
15
+ var _types = require("./types");
16
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
17
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
18
+ var trackChangesPluginKey = exports.trackChangesPluginKey = new _state.PluginKey('trackChangesPlugin');
13
19
  var createTrackChangesPlugin = exports.createTrackChangesPlugin = function createTrackChangesPlugin() {
20
+ // Mark the state to be reset on next time the document has a meaningful change
21
+ var resetBaseline = false;
14
22
  return new _safePlugin.SafePlugin({
15
23
  key: trackChangesPluginKey,
16
24
  state: {
17
- init: function init() {
18
- return {};
25
+ init: function init(_, _ref) {
26
+ var doc = _ref.doc;
27
+ return {
28
+ changes: _prosemirrorChangeset.ChangeSet.create(doc),
29
+ shouldChangesBeDisplayed: false,
30
+ isShowDiffAvailable: false,
31
+ baselineDoc: doc,
32
+ numOfChanges: 0
33
+ };
19
34
  },
20
- apply: function apply(tr, currentPluginState) {
21
- var meta = tr.getMeta(trackChangesPluginKey);
22
- if (meta) {
23
- return meta;
35
+ apply: function apply(tr, state, oldState, newState) {
36
+ var metadata = tr.getMeta(trackChangesPluginKey);
37
+ if (metadata && metadata.action === _types.TOGGLE_TRACK_CHANGES_ACTION.TOGGLE_TRACK_CHANGES) {
38
+ resetBaseline = true;
39
+ return _objectSpread(_objectSpread({}, state), {}, {
40
+ shouldChangesBeDisplayed: !state.shouldChangesBeDisplayed
41
+ });
42
+ }
43
+ var isDocChanged = tr.docChanged && tr.steps.some(function (step) {
44
+ return step instanceof _transform.ReplaceStep || step instanceof _transform.ReplaceAroundStep;
45
+ });
46
+ if (!isDocChanged || tr.getMeta('isRemote') || tr.getMeta('addToHistory') === false) {
47
+ // If no document changes, return the old changeSet
48
+ return state;
49
+ }
50
+ var changes = resetBaseline ? _prosemirrorChangeset.ChangeSet.create(tr.docs[0]).addSteps(tr.doc,
51
+ // The new document
52
+ tr.mapping.maps,
53
+ // The set of changes
54
+ tr.docs[0].content // The old document
55
+ ) : state.changes.addSteps(tr.doc,
56
+ // The new document
57
+ tr.mapping.maps,
58
+ // The set of changes
59
+ tr.docs[0].content // The old document
60
+ );
61
+ var baselineDoc = resetBaseline ? tr.docs[0] : state.baselineDoc;
62
+ resetBaseline = false;
63
+
64
+ // Create a new ChangeSet based on document changes
65
+ return _objectSpread(_objectSpread({}, state), {}, {
66
+ baselineDoc: baselineDoc,
67
+ shouldChangesBeDisplayed: false,
68
+ changes: changes,
69
+ isShowDiffAvailable: true
70
+ });
71
+ }
72
+ },
73
+ props: {
74
+ decorations: function decorations(state) {
75
+ var pluginState = trackChangesPluginKey.getState(state);
76
+ if (!(pluginState !== null && pluginState !== void 0 && pluginState.shouldChangesBeDisplayed) || !pluginState.changes) {
77
+ return undefined;
24
78
  }
25
- return currentPluginState;
79
+ var decoration = _view.DecorationSet.empty;
80
+ var decorations = [];
81
+ var changes = (0, _prosemirrorChangeset.simplifyChanges)(pluginState.changes.changes, state.doc);
82
+ var tr = state.tr;
83
+ changes.forEach(function (change) {
84
+ if (change.inserted.length > 0) {
85
+ decorations.push((0, _decorations.createInlineChangedDecoration)(change));
86
+ }
87
+ if (change.deleted.length > 0) {
88
+ decorations.push((0, _decorations.createDeletedContentDecoration)({
89
+ change: change,
90
+ doc: pluginState === null || pluginState === void 0 ? void 0 : pluginState.baselineDoc,
91
+ tr: tr
92
+ }));
93
+ }
94
+ });
95
+ return decoration.add(tr.doc, decorations);
26
96
  }
27
97
  }
28
98
  });
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.TOGGLE_TRACK_CHANGES_ACTION = void 0;
7
+ var TOGGLE_TRACK_CHANGES_ACTION = exports.TOGGLE_TRACK_CHANGES_ACTION = /*#__PURE__*/function (TOGGLE_TRACK_CHANGES_ACTION) {
8
+ TOGGLE_TRACK_CHANGES_ACTION["TOGGLE_TRACK_CHANGES"] = "TOGGLE_TRACK_CHANGES";
9
+ return TOGGLE_TRACK_CHANGES_ACTION;
10
+ }({});
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.trackChangesPlugin = void 0;
7
7
  var _main = require("./pm-plugins/main");
8
+ var _types = require("./pm-plugins/types");
8
9
  var trackChangesPlugin = exports.trackChangesPlugin = function trackChangesPlugin() {
9
10
  return {
10
11
  name: 'trackChanges',
@@ -15,10 +16,25 @@ var trackChangesPlugin = exports.trackChangesPlugin = function trackChangesPlugi
15
16
  }];
16
17
  },
17
18
  commands: {
18
- setBaseline: function setBaseline(_ref) {
19
+ toggleChanges: function toggleChanges(_ref) {
19
20
  var tr = _ref.tr;
20
- return tr.setMeta('setBaseline', true);
21
+ return tr.setMeta(_main.trackChangesPluginKey, {
22
+ action: _types.TOGGLE_TRACK_CHANGES_ACTION.TOGGLE_TRACK_CHANGES
23
+ });
21
24
  }
25
+ },
26
+ getSharedState: function getSharedState(editorState) {
27
+ var _trackChangesPluginKe, _trackChangesPluginKe2;
28
+ if (!editorState) {
29
+ return {
30
+ isDisplayingChanges: false,
31
+ isShowDiffAvailable: false
32
+ };
33
+ }
34
+ return {
35
+ isDisplayingChanges: Boolean((_trackChangesPluginKe = _main.trackChangesPluginKey.getState(editorState)) === null || _trackChangesPluginKe === void 0 ? void 0 : _trackChangesPluginKe.shouldChangesBeDisplayed),
36
+ isShowDiffAvailable: Boolean((_trackChangesPluginKe2 = _main.trackChangesPluginKey.getState(editorState)) === null || _trackChangesPluginKe2 === void 0 ? void 0 : _trackChangesPluginKe2.isShowDiffAvailable)
37
+ };
22
38
  }
23
39
  };
24
40
  };
@@ -0,0 +1,48 @@
1
+ import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
2
+ import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
3
+ import { Decoration } from '@atlaskit/editor-prosemirror/view';
4
+ const style = convertToInlineCss({
5
+ background: "var(--ds-background-accent-purple-subtlest, #F3F0FF)",
6
+ textDecoration: 'underline',
7
+ textDecorationStyle: 'dotted',
8
+ textDecorationThickness: "var(--ds-space-025, 2px)",
9
+ textDecorationColor: "var(--ds-border-accent-purple, #8270DB)"
10
+ });
11
+
12
+ /**
13
+ * Inline decoration used for insertions as the content already exists in the document
14
+ *
15
+ * @param change Changeset "change" containing information about the change content + range
16
+ * @returns Prosemirror inline decoration
17
+ */
18
+ export const createInlineChangedDecoration = change => Decoration.inline(change.fromB, change.toB, {
19
+ style
20
+ }, {});
21
+ const deletedContentStyle = convertToInlineCss({
22
+ color: "var(--ds-text-accent-gray, #44546F)",
23
+ textDecoration: 'line-through'
24
+ });
25
+
26
+ /**
27
+ * Creates a widget to represent the deleted content in the editor
28
+ *
29
+ * @param props.change Changeset "change" containing information about the change content + range
30
+ * @param props.doc Baseline doc to compare against
31
+ * @param props.tr The relevant transaction this decoration is being created against
32
+ * @returns Prosemirror widget decoration
33
+ */
34
+ export const createDeletedContentDecoration = ({
35
+ change,
36
+ doc,
37
+ tr
38
+ }) => {
39
+ const dom = document.createElement('span');
40
+ dom.setAttribute('style', deletedContentStyle);
41
+ dom.appendChild(DOMSerializer.fromSchema(tr.doc.type.schema).serializeFragment(doc.slice(change.fromA, change.toA).content));
42
+
43
+ // Widget decoration used for deletions as the content is not in the document
44
+ // and we want to display the deleted content with a style.
45
+ return Decoration.widget(change.fromB, dom, {
46
+ marks: []
47
+ });
48
+ };
@@ -1,22 +1,89 @@
1
+ import { ChangeSet, simplifyChanges } from 'prosemirror-changeset';
1
2
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
3
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
3
- export const trackChangesPluginKey = new PluginKey('showDiffPlugin');
4
-
5
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
6
-
4
+ import { ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
5
+ import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
6
+ import { createInlineChangedDecoration, createDeletedContentDecoration } from './decorations';
7
+ import { TOGGLE_TRACK_CHANGES_ACTION as ACTION } from './types';
8
+ export const trackChangesPluginKey = new PluginKey('trackChangesPlugin');
7
9
  export const createTrackChangesPlugin = () => {
10
+ // Mark the state to be reset on next time the document has a meaningful change
11
+ let resetBaseline = false;
8
12
  return new SafePlugin({
9
13
  key: trackChangesPluginKey,
10
14
  state: {
11
- init() {
12
- return {};
15
+ init(_, {
16
+ doc
17
+ }) {
18
+ return {
19
+ changes: ChangeSet.create(doc),
20
+ shouldChangesBeDisplayed: false,
21
+ isShowDiffAvailable: false,
22
+ baselineDoc: doc,
23
+ numOfChanges: 0
24
+ };
13
25
  },
14
- apply: (tr, currentPluginState) => {
15
- const meta = tr.getMeta(trackChangesPluginKey);
16
- if (meta) {
17
- return meta;
26
+ apply(tr, state, oldState, newState) {
27
+ const metadata = tr.getMeta(trackChangesPluginKey);
28
+ if (metadata && metadata.action === ACTION.TOGGLE_TRACK_CHANGES) {
29
+ resetBaseline = true;
30
+ return {
31
+ ...state,
32
+ shouldChangesBeDisplayed: !state.shouldChangesBeDisplayed
33
+ };
34
+ }
35
+ const isDocChanged = tr.docChanged && tr.steps.some(step => step instanceof ReplaceStep || step instanceof ReplaceAroundStep);
36
+ if (!isDocChanged || tr.getMeta('isRemote') || tr.getMeta('addToHistory') === false) {
37
+ // If no document changes, return the old changeSet
38
+ return state;
39
+ }
40
+ const changes = resetBaseline ? ChangeSet.create(tr.docs[0]).addSteps(tr.doc,
41
+ // The new document
42
+ tr.mapping.maps,
43
+ // The set of changes
44
+ tr.docs[0].content // The old document
45
+ ) : state.changes.addSteps(tr.doc,
46
+ // The new document
47
+ tr.mapping.maps,
48
+ // The set of changes
49
+ tr.docs[0].content // The old document
50
+ );
51
+ const baselineDoc = resetBaseline ? tr.docs[0] : state.baselineDoc;
52
+ resetBaseline = false;
53
+
54
+ // Create a new ChangeSet based on document changes
55
+ return {
56
+ ...state,
57
+ baselineDoc,
58
+ shouldChangesBeDisplayed: false,
59
+ changes,
60
+ isShowDiffAvailable: true
61
+ };
62
+ }
63
+ },
64
+ props: {
65
+ decorations: state => {
66
+ const pluginState = trackChangesPluginKey.getState(state);
67
+ if (!(pluginState !== null && pluginState !== void 0 && pluginState.shouldChangesBeDisplayed) || !pluginState.changes) {
68
+ return undefined;
18
69
  }
19
- return currentPluginState;
70
+ const decoration = DecorationSet.empty;
71
+ const decorations = [];
72
+ const changes = simplifyChanges(pluginState.changes.changes, state.doc);
73
+ const tr = state.tr;
74
+ changes.forEach(change => {
75
+ if (change.inserted.length > 0) {
76
+ decorations.push(createInlineChangedDecoration(change));
77
+ }
78
+ if (change.deleted.length > 0) {
79
+ decorations.push(createDeletedContentDecoration({
80
+ change,
81
+ doc: pluginState === null || pluginState === void 0 ? void 0 : pluginState.baselineDoc,
82
+ tr
83
+ }));
84
+ }
85
+ });
86
+ return decoration.add(tr.doc, decorations);
20
87
  }
21
88
  }
22
89
  });
@@ -0,0 +1,4 @@
1
+ export let TOGGLE_TRACK_CHANGES_ACTION = /*#__PURE__*/function (TOGGLE_TRACK_CHANGES_ACTION) {
2
+ TOGGLE_TRACK_CHANGES_ACTION["TOGGLE_TRACK_CHANGES"] = "TOGGLE_TRACK_CHANGES";
3
+ return TOGGLE_TRACK_CHANGES_ACTION;
4
+ }({});
@@ -1,4 +1,5 @@
1
- import { createTrackChangesPlugin } from './pm-plugins/main';
1
+ import { createTrackChangesPlugin, trackChangesPluginKey } from './pm-plugins/main';
2
+ import { TOGGLE_TRACK_CHANGES_ACTION as ACTION } from './pm-plugins/types';
2
3
  export const trackChangesPlugin = () => ({
3
4
  name: 'trackChanges',
4
5
  pmPlugins() {
@@ -8,10 +9,25 @@ export const trackChangesPlugin = () => ({
8
9
  }];
9
10
  },
10
11
  commands: {
11
- setBaseline: ({
12
+ toggleChanges: ({
12
13
  tr
13
14
  }) => {
14
- return tr.setMeta('setBaseline', true);
15
+ return tr.setMeta(trackChangesPluginKey, {
16
+ action: ACTION.TOGGLE_TRACK_CHANGES
17
+ });
15
18
  }
19
+ },
20
+ getSharedState: editorState => {
21
+ var _trackChangesPluginKe, _trackChangesPluginKe2;
22
+ if (!editorState) {
23
+ return {
24
+ isDisplayingChanges: false,
25
+ isShowDiffAvailable: false
26
+ };
27
+ }
28
+ return {
29
+ isDisplayingChanges: Boolean((_trackChangesPluginKe = trackChangesPluginKey.getState(editorState)) === null || _trackChangesPluginKe === void 0 ? void 0 : _trackChangesPluginKe.shouldChangesBeDisplayed),
30
+ isShowDiffAvailable: Boolean((_trackChangesPluginKe2 = trackChangesPluginKey.getState(editorState)) === null || _trackChangesPluginKe2 === void 0 ? void 0 : _trackChangesPluginKe2.isShowDiffAvailable)
31
+ };
16
32
  }
17
33
  });
@@ -0,0 +1,49 @@
1
+ import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
2
+ import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
3
+ import { Decoration } from '@atlaskit/editor-prosemirror/view';
4
+ var style = convertToInlineCss({
5
+ background: "var(--ds-background-accent-purple-subtlest, #F3F0FF)",
6
+ textDecoration: 'underline',
7
+ textDecorationStyle: 'dotted',
8
+ textDecorationThickness: "var(--ds-space-025, 2px)",
9
+ textDecorationColor: "var(--ds-border-accent-purple, #8270DB)"
10
+ });
11
+
12
+ /**
13
+ * Inline decoration used for insertions as the content already exists in the document
14
+ *
15
+ * @param change Changeset "change" containing information about the change content + range
16
+ * @returns Prosemirror inline decoration
17
+ */
18
+ export var createInlineChangedDecoration = function createInlineChangedDecoration(change) {
19
+ return Decoration.inline(change.fromB, change.toB, {
20
+ style: style
21
+ }, {});
22
+ };
23
+ var deletedContentStyle = convertToInlineCss({
24
+ color: "var(--ds-text-accent-gray, #44546F)",
25
+ textDecoration: 'line-through'
26
+ });
27
+
28
+ /**
29
+ * Creates a widget to represent the deleted content in the editor
30
+ *
31
+ * @param props.change Changeset "change" containing information about the change content + range
32
+ * @param props.doc Baseline doc to compare against
33
+ * @param props.tr The relevant transaction this decoration is being created against
34
+ * @returns Prosemirror widget decoration
35
+ */
36
+ export var createDeletedContentDecoration = function createDeletedContentDecoration(_ref) {
37
+ var change = _ref.change,
38
+ doc = _ref.doc,
39
+ tr = _ref.tr;
40
+ var dom = document.createElement('span');
41
+ dom.setAttribute('style', deletedContentStyle);
42
+ dom.appendChild(DOMSerializer.fromSchema(tr.doc.type.schema).serializeFragment(doc.slice(change.fromA, change.toA).content));
43
+
44
+ // Widget decoration used for deletions as the content is not in the document
45
+ // and we want to display the deleted content with a style.
46
+ return Decoration.widget(change.fromB, dom, {
47
+ marks: []
48
+ });
49
+ };
@@ -1,22 +1,91 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ import { ChangeSet, simplifyChanges } from 'prosemirror-changeset';
1
5
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
6
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
3
- export var trackChangesPluginKey = new PluginKey('showDiffPlugin');
4
-
5
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
6
-
7
+ import { ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
8
+ import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
9
+ import { createInlineChangedDecoration, createDeletedContentDecoration } from './decorations';
10
+ import { TOGGLE_TRACK_CHANGES_ACTION as ACTION } from './types';
11
+ export var trackChangesPluginKey = new PluginKey('trackChangesPlugin');
7
12
  export var createTrackChangesPlugin = function createTrackChangesPlugin() {
13
+ // Mark the state to be reset on next time the document has a meaningful change
14
+ var resetBaseline = false;
8
15
  return new SafePlugin({
9
16
  key: trackChangesPluginKey,
10
17
  state: {
11
- init: function init() {
12
- return {};
18
+ init: function init(_, _ref) {
19
+ var doc = _ref.doc;
20
+ return {
21
+ changes: ChangeSet.create(doc),
22
+ shouldChangesBeDisplayed: false,
23
+ isShowDiffAvailable: false,
24
+ baselineDoc: doc,
25
+ numOfChanges: 0
26
+ };
13
27
  },
14
- apply: function apply(tr, currentPluginState) {
15
- var meta = tr.getMeta(trackChangesPluginKey);
16
- if (meta) {
17
- return meta;
28
+ apply: function apply(tr, state, oldState, newState) {
29
+ var metadata = tr.getMeta(trackChangesPluginKey);
30
+ if (metadata && metadata.action === ACTION.TOGGLE_TRACK_CHANGES) {
31
+ resetBaseline = true;
32
+ return _objectSpread(_objectSpread({}, state), {}, {
33
+ shouldChangesBeDisplayed: !state.shouldChangesBeDisplayed
34
+ });
35
+ }
36
+ var isDocChanged = tr.docChanged && tr.steps.some(function (step) {
37
+ return step instanceof ReplaceStep || step instanceof ReplaceAroundStep;
38
+ });
39
+ if (!isDocChanged || tr.getMeta('isRemote') || tr.getMeta('addToHistory') === false) {
40
+ // If no document changes, return the old changeSet
41
+ return state;
42
+ }
43
+ var changes = resetBaseline ? ChangeSet.create(tr.docs[0]).addSteps(tr.doc,
44
+ // The new document
45
+ tr.mapping.maps,
46
+ // The set of changes
47
+ tr.docs[0].content // The old document
48
+ ) : state.changes.addSteps(tr.doc,
49
+ // The new document
50
+ tr.mapping.maps,
51
+ // The set of changes
52
+ tr.docs[0].content // The old document
53
+ );
54
+ var baselineDoc = resetBaseline ? tr.docs[0] : state.baselineDoc;
55
+ resetBaseline = false;
56
+
57
+ // Create a new ChangeSet based on document changes
58
+ return _objectSpread(_objectSpread({}, state), {}, {
59
+ baselineDoc: baselineDoc,
60
+ shouldChangesBeDisplayed: false,
61
+ changes: changes,
62
+ isShowDiffAvailable: true
63
+ });
64
+ }
65
+ },
66
+ props: {
67
+ decorations: function decorations(state) {
68
+ var pluginState = trackChangesPluginKey.getState(state);
69
+ if (!(pluginState !== null && pluginState !== void 0 && pluginState.shouldChangesBeDisplayed) || !pluginState.changes) {
70
+ return undefined;
18
71
  }
19
- return currentPluginState;
72
+ var decoration = DecorationSet.empty;
73
+ var decorations = [];
74
+ var changes = simplifyChanges(pluginState.changes.changes, state.doc);
75
+ var tr = state.tr;
76
+ changes.forEach(function (change) {
77
+ if (change.inserted.length > 0) {
78
+ decorations.push(createInlineChangedDecoration(change));
79
+ }
80
+ if (change.deleted.length > 0) {
81
+ decorations.push(createDeletedContentDecoration({
82
+ change: change,
83
+ doc: pluginState === null || pluginState === void 0 ? void 0 : pluginState.baselineDoc,
84
+ tr: tr
85
+ }));
86
+ }
87
+ });
88
+ return decoration.add(tr.doc, decorations);
20
89
  }
21
90
  }
22
91
  });
@@ -0,0 +1,4 @@
1
+ export var TOGGLE_TRACK_CHANGES_ACTION = /*#__PURE__*/function (TOGGLE_TRACK_CHANGES_ACTION) {
2
+ TOGGLE_TRACK_CHANGES_ACTION["TOGGLE_TRACK_CHANGES"] = "TOGGLE_TRACK_CHANGES";
3
+ return TOGGLE_TRACK_CHANGES_ACTION;
4
+ }({});
@@ -1,4 +1,5 @@
1
- import { createTrackChangesPlugin } from './pm-plugins/main';
1
+ import { createTrackChangesPlugin, trackChangesPluginKey } from './pm-plugins/main';
2
+ import { TOGGLE_TRACK_CHANGES_ACTION as ACTION } from './pm-plugins/types';
2
3
  export var trackChangesPlugin = function trackChangesPlugin() {
3
4
  return {
4
5
  name: 'trackChanges',
@@ -9,10 +10,25 @@ export var trackChangesPlugin = function trackChangesPlugin() {
9
10
  }];
10
11
  },
11
12
  commands: {
12
- setBaseline: function setBaseline(_ref) {
13
+ toggleChanges: function toggleChanges(_ref) {
13
14
  var tr = _ref.tr;
14
- return tr.setMeta('setBaseline', true);
15
+ return tr.setMeta(trackChangesPluginKey, {
16
+ action: ACTION.TOGGLE_TRACK_CHANGES
17
+ });
15
18
  }
19
+ },
20
+ getSharedState: function getSharedState(editorState) {
21
+ var _trackChangesPluginKe, _trackChangesPluginKe2;
22
+ if (!editorState) {
23
+ return {
24
+ isDisplayingChanges: false,
25
+ isShowDiffAvailable: false
26
+ };
27
+ }
28
+ return {
29
+ isDisplayingChanges: Boolean((_trackChangesPluginKe = trackChangesPluginKey.getState(editorState)) === null || _trackChangesPluginKe === void 0 ? void 0 : _trackChangesPluginKe.shouldChangesBeDisplayed),
30
+ isShowDiffAvailable: Boolean((_trackChangesPluginKe2 = trackChangesPluginKey.getState(editorState)) === null || _trackChangesPluginKe2 === void 0 ? void 0 : _trackChangesPluginKe2.isShowDiffAvailable)
31
+ };
16
32
  }
17
33
  };
18
34
  };
@@ -0,0 +1,26 @@
1
+ import type { Change } from 'prosemirror-changeset';
2
+ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
3
+ import type { Transaction } from '@atlaskit/editor-prosemirror/state';
4
+ import { Decoration } from '@atlaskit/editor-prosemirror/view';
5
+ /**
6
+ * Inline decoration used for insertions as the content already exists in the document
7
+ *
8
+ * @param change Changeset "change" containing information about the change content + range
9
+ * @returns Prosemirror inline decoration
10
+ */
11
+ export declare const createInlineChangedDecoration: (change: Change) => Decoration;
12
+ interface DeletedContentDecorationProps {
13
+ change: Change;
14
+ doc: PMNode;
15
+ tr: Transaction;
16
+ }
17
+ /**
18
+ * Creates a widget to represent the deleted content in the editor
19
+ *
20
+ * @param props.change Changeset "change" containing information about the change content + range
21
+ * @param props.doc Baseline doc to compare against
22
+ * @param props.tr The relevant transaction this decoration is being created against
23
+ * @returns Prosemirror widget decoration
24
+ */
25
+ export declare const createDeletedContentDecoration: ({ change, doc, tr, }: DeletedContentDecorationProps) => Decoration;
26
+ export {};
@@ -1,6 +1,13 @@
1
+ import { ChangeSet } from 'prosemirror-changeset';
1
2
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
3
+ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
2
4
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
3
- export declare const trackChangesPluginKey: PluginKey<any>;
4
- type TrackChangesPluginState = {};
5
+ export declare const trackChangesPluginKey: PluginKey<TrackChangesPluginState>;
6
+ type TrackChangesPluginState = {
7
+ shouldChangesBeDisplayed: boolean;
8
+ isShowDiffAvailable: boolean;
9
+ baselineDoc: PMNode;
10
+ changes: ChangeSet;
11
+ };
5
12
  export declare const createTrackChangesPlugin: () => SafePlugin<TrackChangesPluginState>;
6
13
  export {};
@@ -0,0 +1,3 @@
1
+ export declare enum TOGGLE_TRACK_CHANGES_ACTION {
2
+ TOGGLE_TRACK_CHANGES = "TOGGLE_TRACK_CHANGES"
3
+ }
@@ -1,2 +1,22 @@
1
- import type { NextEditorPlugin } from '@atlaskit/editor-common/types';
2
- export type TrackChangesPlugin = NextEditorPlugin<'trackChanges'>;
1
+ import type { EditorCommand, NextEditorPlugin } from '@atlaskit/editor-common/types';
2
+ export type TrackChangesPlugin = NextEditorPlugin<'trackChanges', {
3
+ commands: {
4
+ /**
5
+ * Toggles the displaying of changes in the editor.
6
+ */
7
+ toggleChanges: EditorCommand;
8
+ };
9
+ sharedState: {
10
+ /**
11
+ * Whether the track changes feature is currently displaying changes.
12
+ * Defaults to false.
13
+ */
14
+ isDisplayingChanges: boolean;
15
+ /**
16
+ * If there are changes in the document that determine if track changes button
17
+ * should be enabled.
18
+ * This will only be false initially before any changes in the session.
19
+ */
20
+ isShowDiffAvailable: boolean;
21
+ };
22
+ }>;
@@ -0,0 +1,26 @@
1
+ import type { Change } from 'prosemirror-changeset';
2
+ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
3
+ import type { Transaction } from '@atlaskit/editor-prosemirror/state';
4
+ import { Decoration } from '@atlaskit/editor-prosemirror/view';
5
+ /**
6
+ * Inline decoration used for insertions as the content already exists in the document
7
+ *
8
+ * @param change Changeset "change" containing information about the change content + range
9
+ * @returns Prosemirror inline decoration
10
+ */
11
+ export declare const createInlineChangedDecoration: (change: Change) => Decoration;
12
+ interface DeletedContentDecorationProps {
13
+ change: Change;
14
+ doc: PMNode;
15
+ tr: Transaction;
16
+ }
17
+ /**
18
+ * Creates a widget to represent the deleted content in the editor
19
+ *
20
+ * @param props.change Changeset "change" containing information about the change content + range
21
+ * @param props.doc Baseline doc to compare against
22
+ * @param props.tr The relevant transaction this decoration is being created against
23
+ * @returns Prosemirror widget decoration
24
+ */
25
+ export declare const createDeletedContentDecoration: ({ change, doc, tr, }: DeletedContentDecorationProps) => Decoration;
26
+ export {};
@@ -1,6 +1,13 @@
1
+ import { ChangeSet } from 'prosemirror-changeset';
1
2
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
3
+ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
2
4
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
3
- export declare const trackChangesPluginKey: PluginKey<any>;
4
- type TrackChangesPluginState = {};
5
+ export declare const trackChangesPluginKey: PluginKey<TrackChangesPluginState>;
6
+ type TrackChangesPluginState = {
7
+ shouldChangesBeDisplayed: boolean;
8
+ isShowDiffAvailable: boolean;
9
+ baselineDoc: PMNode;
10
+ changes: ChangeSet;
11
+ };
5
12
  export declare const createTrackChangesPlugin: () => SafePlugin<TrackChangesPluginState>;
6
13
  export {};
@@ -0,0 +1,3 @@
1
+ export declare enum TOGGLE_TRACK_CHANGES_ACTION {
2
+ TOGGLE_TRACK_CHANGES = "TOGGLE_TRACK_CHANGES"
3
+ }
@@ -1,2 +1,22 @@
1
- import type { NextEditorPlugin } from '@atlaskit/editor-common/types';
2
- export type TrackChangesPlugin = NextEditorPlugin<'trackChanges'>;
1
+ import type { EditorCommand, NextEditorPlugin } from '@atlaskit/editor-common/types';
2
+ export type TrackChangesPlugin = NextEditorPlugin<'trackChanges', {
3
+ commands: {
4
+ /**
5
+ * Toggles the displaying of changes in the editor.
6
+ */
7
+ toggleChanges: EditorCommand;
8
+ };
9
+ sharedState: {
10
+ /**
11
+ * Whether the track changes feature is currently displaying changes.
12
+ * Defaults to false.
13
+ */
14
+ isDisplayingChanges: boolean;
15
+ /**
16
+ * If there are changes in the document that determine if track changes button
17
+ * should be enabled.
18
+ * This will only be false initially before any changes in the session.
19
+ */
20
+ isShowDiffAvailable: boolean;
21
+ };
22
+ }>;
package/docs/0-intro.tsx CHANGED
@@ -30,7 +30,72 @@ The \`dependencies\`, \`configuration\`, \`state\`, \`actions\`, and \`commands\
30
30
  below:
31
31
 
32
32
  ${code`
33
- type TrackChangesPlugin = NextEditorPlugin<'trackChanges'>;
33
+ type TrackChangesPlugin = NextEditorPlugin<'trackChanges', {
34
+ commands: {
35
+ toggleChanges: EditorCommand
36
+ }
37
+ }>;
38
+ `}
39
+
40
+ ### Example Usage
41
+ ---
42
+ ${code`
43
+ import React from 'react';
44
+
45
+ import Button from '@atlaskit/button/new';
46
+ import { cssMap } from '@atlaskit/css';
47
+ import { useSharedPluginStateSelector } from '@atlaskit/editor-common/use-shared-plugin-state-selector';
48
+ import { ComposableEditor } from '@atlaskit/editor-core/composable-editor';
49
+ import { usePreset } from '@atlaskit/editor-core/use-preset';
50
+ import { basePlugin } from '@atlaskit/editor-plugins/base';
51
+ import { Box } from '@atlaskit/primitives/compiled';
52
+ import { token } from '@atlaskit/tokens';
53
+
54
+ import { trackChangesPlugin } from '../src/trackChangesPlugin';
55
+
56
+ const styles = cssMap({
57
+ aboveEditor: {
58
+ paddingTop: token('space.100'),
59
+ paddingBottom: token('space.100'),
60
+ },
61
+ everythingContainer: {
62
+ paddingTop: token('space.200'),
63
+ paddingBottom: token('space.200'),
64
+ paddingLeft: token('space.200'),
65
+ paddingRight: token('space.200'),
66
+ },
67
+ });
68
+
69
+ function Editor() {
70
+ const { preset, editorApi } = usePreset(
71
+ (builder) =>
72
+ builder.add(basePlugin).add(trackChangesPlugin),
73
+ [],
74
+ );
75
+
76
+ const isSelected = useSharedPluginStateSelector(editorApi, 'trackChanges.isDisplayingChanges');
77
+
78
+ return (
79
+ <Box xcss={styles.everythingContainer}>
80
+ <Box xcss={styles.aboveEditor}>
81
+ <Button
82
+ appearance="primary"
83
+ onClick={() => {
84
+ editorApi?.core.actions.execute(
85
+ editorApi?.trackChanges.commands.toggleChanges,
86
+ );
87
+ }}
88
+ isSelected={isSelected}
89
+ >
90
+ Show Diff
91
+ </Button>
92
+ </Box>
93
+ <ComposableEditor preset={preset} />
94
+ </Box>
95
+ );
96
+ }
97
+
98
+ export default Editor;
34
99
  `}
35
100
 
36
101
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-track-changes",
3
- "version": "1.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "ShowDiff plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -32,10 +32,12 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@atlaskit/editor-prosemirror": "7.0.0",
35
- "@babel/runtime": "^7.0.0"
35
+ "@atlaskit/tokens": "^5.6.0",
36
+ "@babel/runtime": "^7.0.0",
37
+ "prosemirror-changeset": "^2.2.1"
36
38
  },
37
39
  "peerDependencies": {
38
- "@atlaskit/editor-common": "^107.7.0",
40
+ "@atlaskit/editor-common": "^107.9.0",
39
41
  "react": "^18.2.0"
40
42
  },
41
43
  "devDependencies": {