@atlaskit/editor-plugin-text-formatting 0.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.
Files changed (140) hide show
  1. package/.eslintrc.js +7 -0
  2. package/CHANGELOG.md +1 -0
  3. package/LICENSE.md +13 -0
  4. package/README.md +9 -0
  5. package/dist/cjs/actions.js +188 -0
  6. package/dist/cjs/commands/clear-formatting.js +111 -0
  7. package/dist/cjs/commands/text-formatting.js +143 -0
  8. package/dist/cjs/commands/transform-to-code.js +68 -0
  9. package/dist/cjs/index.js +12 -0
  10. package/dist/cjs/plugin.js +133 -0
  11. package/dist/cjs/pm-plugins/clear-formatting-keymap.js +21 -0
  12. package/dist/cjs/pm-plugins/clear-formatting.js +36 -0
  13. package/dist/cjs/pm-plugins/cursor.js +55 -0
  14. package/dist/cjs/pm-plugins/input-rule.js +274 -0
  15. package/dist/cjs/pm-plugins/keymap.js +52 -0
  16. package/dist/cjs/pm-plugins/main.js +113 -0
  17. package/dist/cjs/pm-plugins/plugin-key.js +9 -0
  18. package/dist/cjs/pm-plugins/smart-input-rule.js +176 -0
  19. package/dist/cjs/ui/Toolbar/constants.js +19 -0
  20. package/dist/cjs/ui/Toolbar/dropdown-menu.js +86 -0
  21. package/dist/cjs/ui/Toolbar/hooks/clear-formatting-icon.js +55 -0
  22. package/dist/cjs/ui/Toolbar/hooks/formatting-icons.js +227 -0
  23. package/dist/cjs/ui/Toolbar/hooks/menu-state.js +23 -0
  24. package/dist/cjs/ui/Toolbar/hooks/responsive-toolbar-buttons.js +60 -0
  25. package/dist/cjs/ui/Toolbar/index.js +183 -0
  26. package/dist/cjs/ui/Toolbar/more-button.js +42 -0
  27. package/dist/cjs/ui/Toolbar/single-toolbar-buttons.js +49 -0
  28. package/dist/cjs/ui/Toolbar/types.js +17 -0
  29. package/dist/cjs/utils/cell-selection.js +12 -0
  30. package/dist/cjs/utils.js +86 -0
  31. package/dist/cjs/version.json +5 -0
  32. package/dist/es2019/actions.js +161 -0
  33. package/dist/es2019/commands/clear-formatting.js +105 -0
  34. package/dist/es2019/commands/text-formatting.js +144 -0
  35. package/dist/es2019/commands/transform-to-code.js +71 -0
  36. package/dist/es2019/index.js +1 -0
  37. package/dist/es2019/plugin.js +124 -0
  38. package/dist/es2019/pm-plugins/clear-formatting-keymap.js +10 -0
  39. package/dist/es2019/pm-plugins/clear-formatting.js +26 -0
  40. package/dist/es2019/pm-plugins/cursor.js +52 -0
  41. package/dist/es2019/pm-plugins/input-rule.js +242 -0
  42. package/dist/es2019/pm-plugins/keymap.js +43 -0
  43. package/dist/es2019/pm-plugins/main.js +110 -0
  44. package/dist/es2019/pm-plugins/plugin-key.js +2 -0
  45. package/dist/es2019/pm-plugins/smart-input-rule.js +155 -0
  46. package/dist/es2019/ui/Toolbar/constants.js +20 -0
  47. package/dist/es2019/ui/Toolbar/dropdown-menu.js +66 -0
  48. package/dist/es2019/ui/Toolbar/hooks/clear-formatting-icon.js +44 -0
  49. package/dist/es2019/ui/Toolbar/hooks/formatting-icons.js +212 -0
  50. package/dist/es2019/ui/Toolbar/hooks/menu-state.js +11 -0
  51. package/dist/es2019/ui/Toolbar/hooks/responsive-toolbar-buttons.js +48 -0
  52. package/dist/es2019/ui/Toolbar/index.js +168 -0
  53. package/dist/es2019/ui/Toolbar/more-button.js +34 -0
  54. package/dist/es2019/ui/Toolbar/single-toolbar-buttons.js +39 -0
  55. package/dist/es2019/ui/Toolbar/types.js +10 -0
  56. package/dist/es2019/utils/cell-selection.js +5 -0
  57. package/dist/es2019/utils.js +74 -0
  58. package/dist/es2019/version.json +5 -0
  59. package/dist/esm/actions.js +168 -0
  60. package/dist/esm/commands/clear-formatting.js +101 -0
  61. package/dist/esm/commands/text-formatting.js +134 -0
  62. package/dist/esm/commands/transform-to-code.js +61 -0
  63. package/dist/esm/index.js +1 -0
  64. package/dist/esm/plugin.js +125 -0
  65. package/dist/esm/pm-plugins/clear-formatting-keymap.js +10 -0
  66. package/dist/esm/pm-plugins/clear-formatting.js +28 -0
  67. package/dist/esm/pm-plugins/cursor.js +48 -0
  68. package/dist/esm/pm-plugins/input-rule.js +257 -0
  69. package/dist/esm/pm-plugins/keymap.js +43 -0
  70. package/dist/esm/pm-plugins/main.js +99 -0
  71. package/dist/esm/pm-plugins/plugin-key.js +2 -0
  72. package/dist/esm/pm-plugins/smart-input-rule.js +169 -0
  73. package/dist/esm/ui/Toolbar/constants.js +8 -0
  74. package/dist/esm/ui/Toolbar/dropdown-menu.js +75 -0
  75. package/dist/esm/ui/Toolbar/hooks/clear-formatting-icon.js +47 -0
  76. package/dist/esm/ui/Toolbar/hooks/formatting-icons.js +215 -0
  77. package/dist/esm/ui/Toolbar/hooks/menu-state.js +15 -0
  78. package/dist/esm/ui/Toolbar/hooks/responsive-toolbar-buttons.js +50 -0
  79. package/dist/esm/ui/Toolbar/index.js +174 -0
  80. package/dist/esm/ui/Toolbar/more-button.js +33 -0
  81. package/dist/esm/ui/Toolbar/single-toolbar-buttons.js +38 -0
  82. package/dist/esm/ui/Toolbar/types.js +10 -0
  83. package/dist/esm/utils/cell-selection.js +5 -0
  84. package/dist/esm/utils.js +75 -0
  85. package/dist/esm/version.json +5 -0
  86. package/dist/types/actions.d.ts +22 -0
  87. package/dist/types/commands/clear-formatting.d.ts +6 -0
  88. package/dist/types/commands/text-formatting.d.ts +5 -0
  89. package/dist/types/commands/transform-to-code.d.ts +2 -0
  90. package/dist/types/index.d.ts +3 -0
  91. package/dist/types/plugin.d.ts +17 -0
  92. package/dist/types/pm-plugins/clear-formatting-keymap.d.ts +4 -0
  93. package/dist/types/pm-plugins/clear-formatting.d.ts +8 -0
  94. package/dist/types/pm-plugins/cursor.d.ts +3 -0
  95. package/dist/types/pm-plugins/input-rule.d.ts +23 -0
  96. package/dist/types/pm-plugins/keymap.d.ts +4 -0
  97. package/dist/types/pm-plugins/main.d.ts +7 -0
  98. package/dist/types/pm-plugins/plugin-key.d.ts +3 -0
  99. package/dist/types/pm-plugins/smart-input-rule.d.ts +3 -0
  100. package/dist/types/ui/Toolbar/constants.d.ts +6 -0
  101. package/dist/types/ui/Toolbar/dropdown-menu.d.ts +15 -0
  102. package/dist/types/ui/Toolbar/hooks/clear-formatting-icon.d.ts +7 -0
  103. package/dist/types/ui/Toolbar/hooks/formatting-icons.d.ts +14 -0
  104. package/dist/types/ui/Toolbar/hooks/menu-state.d.ts +1 -0
  105. package/dist/types/ui/Toolbar/hooks/responsive-toolbar-buttons.d.ts +20 -0
  106. package/dist/types/ui/Toolbar/index.d.ts +25 -0
  107. package/dist/types/ui/Toolbar/more-button.d.ts +14 -0
  108. package/dist/types/ui/Toolbar/single-toolbar-buttons.d.ts +10 -0
  109. package/dist/types/ui/Toolbar/types.d.ts +32 -0
  110. package/dist/types/utils/cell-selection.d.ts +3 -0
  111. package/dist/types/utils.d.ts +11 -0
  112. package/dist/types-ts4.5/actions.d.ts +22 -0
  113. package/dist/types-ts4.5/commands/clear-formatting.d.ts +6 -0
  114. package/dist/types-ts4.5/commands/text-formatting.d.ts +5 -0
  115. package/dist/types-ts4.5/commands/transform-to-code.d.ts +2 -0
  116. package/dist/types-ts4.5/index.d.ts +3 -0
  117. package/dist/types-ts4.5/plugin.d.ts +19 -0
  118. package/dist/types-ts4.5/pm-plugins/clear-formatting-keymap.d.ts +4 -0
  119. package/dist/types-ts4.5/pm-plugins/clear-formatting.d.ts +8 -0
  120. package/dist/types-ts4.5/pm-plugins/cursor.d.ts +3 -0
  121. package/dist/types-ts4.5/pm-plugins/input-rule.d.ts +23 -0
  122. package/dist/types-ts4.5/pm-plugins/keymap.d.ts +4 -0
  123. package/dist/types-ts4.5/pm-plugins/main.d.ts +7 -0
  124. package/dist/types-ts4.5/pm-plugins/plugin-key.d.ts +3 -0
  125. package/dist/types-ts4.5/pm-plugins/smart-input-rule.d.ts +3 -0
  126. package/dist/types-ts4.5/ui/Toolbar/constants.d.ts +6 -0
  127. package/dist/types-ts4.5/ui/Toolbar/dropdown-menu.d.ts +15 -0
  128. package/dist/types-ts4.5/ui/Toolbar/hooks/clear-formatting-icon.d.ts +7 -0
  129. package/dist/types-ts4.5/ui/Toolbar/hooks/formatting-icons.d.ts +14 -0
  130. package/dist/types-ts4.5/ui/Toolbar/hooks/menu-state.d.ts +5 -0
  131. package/dist/types-ts4.5/ui/Toolbar/hooks/responsive-toolbar-buttons.d.ts +20 -0
  132. package/dist/types-ts4.5/ui/Toolbar/index.d.ts +25 -0
  133. package/dist/types-ts4.5/ui/Toolbar/more-button.d.ts +14 -0
  134. package/dist/types-ts4.5/ui/Toolbar/single-toolbar-buttons.d.ts +10 -0
  135. package/dist/types-ts4.5/ui/Toolbar/types.d.ts +32 -0
  136. package/dist/types-ts4.5/utils/cell-selection.d.ts +3 -0
  137. package/dist/types-ts4.5/utils.d.ts +11 -0
  138. package/package.json +93 -0
  139. package/report.api.md +66 -0
  140. package/tmp/api-report-tmp.d.ts +39 -0
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.markActive = exports.isArrayContainsContent = exports.hasCode = exports.compareItemsArrays = exports.checkFormattingIsPresent = void 0;
7
+ var _mark = require("@atlaskit/editor-common/mark");
8
+ var _clearFormatting = require("./commands/clear-formatting");
9
+ var hasCode = function hasCode(state, pos) {
10
+ var code = state.schema.marks.code;
11
+ var node = pos >= 0 && state.doc.nodeAt(pos);
12
+ if (node) {
13
+ return !!node.marks.filter(function (mark) {
14
+ return mark.type === code;
15
+ }).length;
16
+ }
17
+ return false;
18
+ };
19
+
20
+ /**
21
+ * Determine if a mark (with specific attribute values) exists anywhere in the selection.
22
+ */
23
+ exports.hasCode = hasCode;
24
+ var markActive = function markActive(state, mark) {
25
+ var _state$selection = state.selection,
26
+ from = _state$selection.from,
27
+ to = _state$selection.to,
28
+ empty = _state$selection.empty;
29
+ // When the selection is empty, only the active marks apply.
30
+ if (empty) {
31
+ return !!mark.isInSet(state.tr.storedMarks || state.selection.$from.marks());
32
+ }
33
+ // For a non-collapsed selection, the marks on the nodes matter.
34
+ var found = false;
35
+ state.doc.nodesBetween(from, to, function (node) {
36
+ found = found || mark.isInSet(node.marks);
37
+ });
38
+ return found;
39
+ };
40
+ exports.markActive = markActive;
41
+ var blockStylingIsPresent = function blockStylingIsPresent(state) {
42
+ var _state$selection2 = state.selection,
43
+ from = _state$selection2.from,
44
+ to = _state$selection2.to;
45
+ var isBlockStyling = false;
46
+ state.doc.nodesBetween(from, to, function (node) {
47
+ if (_clearFormatting.FORMATTING_NODE_TYPES.indexOf(node.type.name) !== -1) {
48
+ isBlockStyling = true;
49
+ return false;
50
+ }
51
+ return true;
52
+ });
53
+ return isBlockStyling;
54
+ };
55
+ var marksArePresent = function marksArePresent(state) {
56
+ var activeMarkTypes = _clearFormatting.FORMATTING_MARK_TYPES.filter(function (mark) {
57
+ if (!!state.schema.marks[mark]) {
58
+ var _state$selection3 = state.selection,
59
+ $from = _state$selection3.$from,
60
+ empty = _state$selection3.empty;
61
+ var marks = state.schema.marks;
62
+ if (empty) {
63
+ return !!marks[mark].isInSet(state.storedMarks || $from.marks());
64
+ }
65
+ return (0, _mark.anyMarkActive)(state, marks[mark]);
66
+ }
67
+ return false;
68
+ });
69
+ return activeMarkTypes.length > 0;
70
+ };
71
+ var checkFormattingIsPresent = function checkFormattingIsPresent(state) {
72
+ return marksArePresent(state) || blockStylingIsPresent(state);
73
+ };
74
+ exports.checkFormattingIsPresent = checkFormattingIsPresent;
75
+ var compareItemsArrays = function compareItemsArrays(items, prevItems) {
76
+ return items && items.filter(function (item) {
77
+ return !prevItems.includes(item);
78
+ });
79
+ };
80
+ exports.compareItemsArrays = compareItemsArrays;
81
+ var isArrayContainsContent = function isArrayContainsContent(items, content) {
82
+ return items.filter(function (item) {
83
+ return item.content === content;
84
+ }).length > 0;
85
+ };
86
+ exports.isArrayContainsContent = isArrayContainsContent;
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "@atlaskit/editor-plugin-text-formatting",
3
+ "version": "0.1.0",
4
+ "sideEffects": false
5
+ }
@@ -0,0 +1,161 @@
1
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
2
+ import { withAnalytics } from '@atlaskit/editor-common/editor-analytics';
3
+ import { toggleMark } from '@atlaskit/editor-common/mark';
4
+ export const toggleEm = () => {
5
+ return (state, dispatch) => {
6
+ const {
7
+ em
8
+ } = state.schema.marks;
9
+ if (em) {
10
+ return toggleMark(em)(state, dispatch);
11
+ }
12
+ return false;
13
+ };
14
+ };
15
+ export const toggleEmWithAnalytics = editorAnalyticsAPI => ({
16
+ inputMethod
17
+ }) => withAnalytics(editorAnalyticsAPI, {
18
+ action: ACTION.FORMATTED,
19
+ actionSubject: ACTION_SUBJECT.TEXT,
20
+ eventType: EVENT_TYPE.TRACK,
21
+ actionSubjectId: ACTION_SUBJECT_ID.FORMAT_ITALIC,
22
+ attributes: {
23
+ inputMethod
24
+ }
25
+ })(toggleEm());
26
+ export const toggleStrike = () => {
27
+ return (state, dispatch) => {
28
+ const {
29
+ strike
30
+ } = state.schema.marks;
31
+ if (strike) {
32
+ return toggleMark(strike)(state, dispatch);
33
+ }
34
+ return false;
35
+ };
36
+ };
37
+ export const toggleStrikeWithAnalytics = editorAnalyticsAPI => ({
38
+ inputMethod
39
+ }) => withAnalytics(editorAnalyticsAPI, {
40
+ action: ACTION.FORMATTED,
41
+ actionSubject: ACTION_SUBJECT.TEXT,
42
+ eventType: EVENT_TYPE.TRACK,
43
+ actionSubjectId: ACTION_SUBJECT_ID.FORMAT_STRIKE,
44
+ attributes: {
45
+ inputMethod
46
+ }
47
+ })(toggleStrike());
48
+ export const toggleStrong = () => {
49
+ return (state, dispatch) => {
50
+ const {
51
+ strong
52
+ } = state.schema.marks;
53
+ if (strong) {
54
+ return toggleMark(strong)(state, dispatch);
55
+ }
56
+ return false;
57
+ };
58
+ };
59
+ export const toggleStrongWithAnalytics = editorAnalyticsAPI => ({
60
+ inputMethod
61
+ }) => withAnalytics(editorAnalyticsAPI, {
62
+ action: ACTION.FORMATTED,
63
+ actionSubject: ACTION_SUBJECT.TEXT,
64
+ eventType: EVENT_TYPE.TRACK,
65
+ actionSubjectId: ACTION_SUBJECT_ID.FORMAT_STRONG,
66
+ attributes: {
67
+ inputMethod
68
+ }
69
+ })(toggleStrong());
70
+ export const toggleUnderline = () => {
71
+ return (state, dispatch) => {
72
+ const {
73
+ underline
74
+ } = state.schema.marks;
75
+ if (underline) {
76
+ return toggleMark(underline)(state, dispatch);
77
+ }
78
+ return false;
79
+ };
80
+ };
81
+ export const toggleUnderlineWithAnalytics = editorAnalyticsAPI => ({
82
+ inputMethod
83
+ }) => withAnalytics(editorAnalyticsAPI, {
84
+ action: ACTION.FORMATTED,
85
+ actionSubject: ACTION_SUBJECT.TEXT,
86
+ eventType: EVENT_TYPE.TRACK,
87
+ actionSubjectId: ACTION_SUBJECT_ID.FORMAT_UNDERLINE,
88
+ attributes: {
89
+ inputMethod
90
+ }
91
+ })(toggleUnderline());
92
+ export const toggleSuperscript = () => {
93
+ return (state, dispatch) => {
94
+ const {
95
+ subsup
96
+ } = state.schema.marks;
97
+ if (subsup) {
98
+ return toggleMark(subsup, {
99
+ type: 'sup'
100
+ })(state, dispatch);
101
+ }
102
+ return false;
103
+ };
104
+ };
105
+ export const toggleSuperscriptWithAnalytics = editorAnalyticsAPI => ({
106
+ inputMethod
107
+ }) => withAnalytics(editorAnalyticsAPI, {
108
+ action: ACTION.FORMATTED,
109
+ actionSubject: ACTION_SUBJECT.TEXT,
110
+ eventType: EVENT_TYPE.TRACK,
111
+ actionSubjectId: ACTION_SUBJECT_ID.FORMAT_SUPER,
112
+ attributes: {
113
+ inputMethod
114
+ }
115
+ })(toggleSuperscript());
116
+ export const toggleSubscript = () => {
117
+ return (state, dispatch) => {
118
+ const {
119
+ subsup
120
+ } = state.schema.marks;
121
+ if (subsup) {
122
+ return toggleMark(subsup, {
123
+ type: 'sub'
124
+ })(state, dispatch);
125
+ }
126
+ return false;
127
+ };
128
+ };
129
+ export const toggleSubscriptWithAnalytics = editorAnalyticsAPI => ({
130
+ inputMethod
131
+ }) => withAnalytics(editorAnalyticsAPI, {
132
+ action: ACTION.FORMATTED,
133
+ actionSubject: ACTION_SUBJECT.TEXT,
134
+ eventType: EVENT_TYPE.TRACK,
135
+ actionSubjectId: ACTION_SUBJECT_ID.FORMAT_SUB,
136
+ attributes: {
137
+ inputMethod
138
+ }
139
+ })(toggleSubscript());
140
+ export const toggleCode = () => {
141
+ return (state, dispatch) => {
142
+ const {
143
+ code
144
+ } = state.schema.marks;
145
+ if (code) {
146
+ return toggleMark(code)(state, dispatch);
147
+ }
148
+ return false;
149
+ };
150
+ };
151
+ export const toggleCodeWithAnalytics = editorAnalyticsAPI => ({
152
+ inputMethod
153
+ }) => withAnalytics(editorAnalyticsAPI, {
154
+ action: ACTION.FORMATTED,
155
+ actionSubject: ACTION_SUBJECT.TEXT,
156
+ eventType: EVENT_TYPE.TRACK,
157
+ actionSubjectId: ACTION_SUBJECT_ID.FORMAT_CODE,
158
+ attributes: {
159
+ inputMethod
160
+ }
161
+ })(toggleCode());
@@ -0,0 +1,105 @@
1
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
2
+ import { liftTarget } from '@atlaskit/editor-prosemirror/transform';
3
+ import { CellSelection } from '@atlaskit/editor-tables/cell-selection';
4
+ import { cellSelectionNodesBetween } from '../utils/cell-selection';
5
+ export const FORMATTING_NODE_TYPES = ['heading', 'blockquote'];
6
+ export const FORMATTING_MARK_TYPES = ['em', 'code', 'strike', 'strong', 'underline', 'textColor', 'subsup'];
7
+ const formatTypes = {
8
+ em: ACTION_SUBJECT_ID.FORMAT_ITALIC,
9
+ code: ACTION_SUBJECT_ID.FORMAT_CODE,
10
+ strike: ACTION_SUBJECT_ID.FORMAT_STRIKE,
11
+ strong: ACTION_SUBJECT_ID.FORMAT_STRONG,
12
+ underline: ACTION_SUBJECT_ID.FORMAT_UNDERLINE,
13
+ textColor: ACTION_SUBJECT_ID.FORMAT_COLOR,
14
+ subsup: 'subsup'
15
+ };
16
+ export function clearFormattingWithAnalytics(inputMethod, editorAnalyticsAPI) {
17
+ return clearFormatting(inputMethod, editorAnalyticsAPI);
18
+ }
19
+ function clearNodeFormattingOnSelection(state, tr, formattedNodeType, nodeName, formattingCleared) {
20
+ return function (node, pos) {
21
+ if (node.type === formattedNodeType) {
22
+ if (formattedNodeType.isTextblock) {
23
+ tr.setNodeMarkup(pos, state.schema.nodes.paragraph);
24
+ formattingCleared.push(nodeName);
25
+ return false;
26
+ } else {
27
+ // In case of panel or blockquote
28
+ let fromPos = tr.doc.resolve(pos + 1);
29
+ let toPos = tr.doc.resolve(pos + node.nodeSize - 1);
30
+ const nodeRange = fromPos.blockRange(toPos);
31
+ if (nodeRange) {
32
+ const targetLiftDepth = liftTarget(nodeRange);
33
+ if (targetLiftDepth || targetLiftDepth === 0) {
34
+ formattingCleared.push(nodeName);
35
+ tr.lift(nodeRange, targetLiftDepth);
36
+ }
37
+ }
38
+ }
39
+ }
40
+ return true;
41
+ };
42
+ }
43
+ export function clearFormatting(inputMethod, editorAnalyticsAPI) {
44
+ return function (state, dispatch) {
45
+ const {
46
+ tr
47
+ } = state;
48
+ const formattingCleared = [];
49
+ FORMATTING_MARK_TYPES.forEach(mark => {
50
+ const {
51
+ from,
52
+ to
53
+ } = tr.selection;
54
+ const markType = state.schema.marks[mark];
55
+ if (!markType) {
56
+ return;
57
+ }
58
+ if (tr.selection instanceof CellSelection) {
59
+ cellSelectionNodesBetween(tr.selection, tr.doc, (node, pos) => {
60
+ const isTableCell = node.type === state.schema.nodes.tableCell || node.type === state.schema.nodes.tableHeader;
61
+ if (!isTableCell) {
62
+ return true;
63
+ }
64
+ if (tr.doc.rangeHasMark(pos, pos + node.nodeSize, markType)) {
65
+ formattingCleared.push(formatTypes[mark]);
66
+ tr.removeMark(pos, pos + node.nodeSize, markType);
67
+ }
68
+ return false;
69
+ });
70
+ } else if (tr.doc.rangeHasMark(from, to, markType)) {
71
+ formattingCleared.push(formatTypes[mark]);
72
+ tr.removeMark(from, to, markType);
73
+ }
74
+ });
75
+ FORMATTING_NODE_TYPES.forEach(nodeName => {
76
+ const formattedNodeType = state.schema.nodes[nodeName];
77
+ const {
78
+ $from,
79
+ $to
80
+ } = tr.selection;
81
+ if (tr.selection instanceof CellSelection) {
82
+ cellSelectionNodesBetween(tr.selection, tr.doc, clearNodeFormattingOnSelection(state, tr, formattedNodeType, nodeName, formattingCleared));
83
+ } else {
84
+ tr.doc.nodesBetween($from.pos, $to.pos, clearNodeFormattingOnSelection(state, tr, formattedNodeType, nodeName, formattingCleared));
85
+ }
86
+ });
87
+ tr.setStoredMarks([]);
88
+ if (formattingCleared.length && inputMethod) {
89
+ editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent({
90
+ action: ACTION.FORMATTED,
91
+ eventType: EVENT_TYPE.TRACK,
92
+ actionSubject: ACTION_SUBJECT.TEXT,
93
+ actionSubjectId: ACTION_SUBJECT_ID.FORMAT_CLEAR,
94
+ attributes: {
95
+ inputMethod,
96
+ formattingCleared
97
+ }
98
+ })(tr);
99
+ }
100
+ if (dispatch) {
101
+ dispatch(tr);
102
+ }
103
+ return true;
104
+ };
105
+ }
@@ -0,0 +1,144 @@
1
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
2
+ import { withAnalytics } from '@atlaskit/editor-common/editor-analytics';
3
+ import { applyMarkOnRange } from '@atlaskit/editor-common/mark';
4
+ import { Selection } from '@atlaskit/editor-prosemirror/state';
5
+ import { hasCode, markActive } from '../utils';
6
+ export const moveRight = () => {
7
+ return (state, dispatch) => {
8
+ const {
9
+ code
10
+ } = state.schema.marks;
11
+ const {
12
+ empty,
13
+ $cursor
14
+ } = state.selection;
15
+ if (!empty || !$cursor) {
16
+ return false;
17
+ }
18
+ const {
19
+ storedMarks
20
+ } = state.tr;
21
+ if (code) {
22
+ const insideCode = markActive(state, code.create());
23
+ const currentPosHasCode = state.doc.rangeHasMark($cursor.pos, $cursor.pos, code);
24
+ const nextPosHasCode = state.doc.rangeHasMark($cursor.pos, $cursor.pos + 1, code);
25
+ const exitingCode = !currentPosHasCode && !nextPosHasCode && (!storedMarks || !!storedMarks.length);
26
+ const enteringCode = !currentPosHasCode && nextPosHasCode && (!storedMarks || !storedMarks.length);
27
+
28
+ // entering code mark (from the left edge): don't move the cursor, just add the mark
29
+ if (!insideCode && enteringCode) {
30
+ if (dispatch) {
31
+ dispatch(state.tr.addStoredMark(code.create()));
32
+ }
33
+ return true;
34
+ }
35
+
36
+ // exiting code mark: don't move the cursor, just remove the mark
37
+ if (insideCode && exitingCode) {
38
+ if (dispatch) {
39
+ dispatch(state.tr.removeStoredMark(code));
40
+ }
41
+ return true;
42
+ }
43
+ }
44
+ return false;
45
+ };
46
+ };
47
+ export const moveLeft = () => {
48
+ return (state, dispatch) => {
49
+ const {
50
+ code
51
+ } = state.schema.marks;
52
+ const {
53
+ empty,
54
+ $cursor
55
+ } = state.selection;
56
+ if (!empty || !$cursor) {
57
+ return false;
58
+ }
59
+ const {
60
+ storedMarks
61
+ } = state.tr;
62
+ if (code) {
63
+ const insideCode = code && markActive(state, code.create());
64
+ const currentPosHasCode = hasCode(state, $cursor.pos);
65
+ const nextPosHasCode = hasCode(state, $cursor.pos - 1);
66
+ const nextNextPosHasCode = hasCode(state, $cursor.pos - 2);
67
+ const exitingCode = currentPosHasCode && !nextPosHasCode && Array.isArray(storedMarks);
68
+ const atLeftEdge = nextPosHasCode && !nextNextPosHasCode && (storedMarks === null || Array.isArray(storedMarks) && !!storedMarks.length);
69
+ const atRightEdge = (exitingCode && Array.isArray(storedMarks) && !storedMarks.length || !exitingCode && storedMarks === null) && !nextPosHasCode && nextNextPosHasCode;
70
+ const enteringCode = !currentPosHasCode && nextPosHasCode && Array.isArray(storedMarks) && !storedMarks.length;
71
+
72
+ // at the right edge: remove code mark and move the cursor to the left
73
+ if (!insideCode && atRightEdge) {
74
+ const tr = state.tr.setSelection(Selection.near(state.doc.resolve($cursor.pos - 1)));
75
+ if (dispatch) {
76
+ dispatch(tr.removeStoredMark(code));
77
+ }
78
+ return true;
79
+ }
80
+
81
+ // entering code mark (from right edge): don't move the cursor, just add the mark
82
+ if (!insideCode && enteringCode) {
83
+ if (dispatch) {
84
+ dispatch(state.tr.addStoredMark(code.create()));
85
+ }
86
+ return true;
87
+ }
88
+
89
+ // at the left edge: add code mark and move the cursor to the left
90
+ if (insideCode && atLeftEdge) {
91
+ const tr = state.tr.setSelection(Selection.near(state.doc.resolve($cursor.pos - 1)));
92
+ if (dispatch) {
93
+ dispatch(tr.addStoredMark(code.create()));
94
+ }
95
+ return true;
96
+ }
97
+
98
+ // exiting code mark (or at the beginning of the line): don't move the cursor, just remove the mark
99
+ const isFirstChild = $cursor.index($cursor.depth - 1) === 0;
100
+ if (insideCode && (exitingCode || !$cursor.nodeBefore && isFirstChild)) {
101
+ if (dispatch) {
102
+ dispatch(state.tr.removeStoredMark(code));
103
+ }
104
+ return true;
105
+ }
106
+ }
107
+ return false;
108
+ };
109
+ };
110
+ const createInlineCodeFromTextInput = (from, to, text) => {
111
+ return (state, dispatch) => {
112
+ if (state.selection.empty) {
113
+ const {
114
+ nodeBefore: before
115
+ } = state.doc.resolve(from);
116
+ const {
117
+ nodeAfter: after
118
+ } = state.doc.resolve(to);
119
+ const hasTickBefore = before && before.text && before.text.endsWith('`');
120
+ const hasTickAfter = after && after.text && after.text.startsWith('`');
121
+ if (hasTickBefore && hasTickAfter) {
122
+ let tr = state.tr.replaceRangeWith(from - 1, to + 1, state.schema.text(text));
123
+ if (dispatch) {
124
+ const codeMark = state.schema.marks.code.create();
125
+ tr = applyMarkOnRange(tr.mapping.map(from - 1), tr.mapping.map(to + 1), false, codeMark, tr).setStoredMarks([codeMark]);
126
+ dispatch(tr);
127
+ }
128
+ return true;
129
+ }
130
+ }
131
+ return false;
132
+ };
133
+ };
134
+ export const createInlineCodeFromTextInputWithAnalytics = editorAnalyticsAPI => (from, to, text) => {
135
+ return withAnalytics(editorAnalyticsAPI, {
136
+ action: ACTION.FORMATTED,
137
+ actionSubject: ACTION_SUBJECT.TEXT,
138
+ eventType: EVENT_TYPE.TRACK,
139
+ actionSubjectId: ACTION_SUBJECT_ID.FORMAT_CODE,
140
+ attributes: {
141
+ inputMethod: INPUT_METHOD.FORMATTING
142
+ }
143
+ })(createInlineCodeFromTextInput(from, to, text));
144
+ };
@@ -0,0 +1,71 @@
1
+ import { filterChildrenBetween } from '@atlaskit/editor-common/mark';
2
+ const SMART_TO_ASCII = {
3
+ '…': '...',
4
+ '→': '->',
5
+ '←': '<-',
6
+ '–': '--',
7
+ '“': '"',
8
+ '”': '"',
9
+ '‘': "'",
10
+ '’': "'"
11
+ };
12
+ const FIND_SMART_CHAR = new RegExp(`[${Object.keys(SMART_TO_ASCII).join('')}]`, 'g');
13
+ const replaceMentionOrEmojiForTextContent = (position, nodeSize, textContent, tr) => {
14
+ const currentPos = tr.mapping.map(position);
15
+ const {
16
+ schema
17
+ } = tr.doc.type;
18
+ tr.replaceWith(currentPos, currentPos + nodeSize, schema.text(textContent));
19
+ };
20
+ const replaceSmartCharsToAscii = (position, textContent, tr) => {
21
+ const {
22
+ schema
23
+ } = tr.doc.type;
24
+ let match;
25
+ while (match = FIND_SMART_CHAR.exec(textContent)) {
26
+ const {
27
+ 0: smartChar,
28
+ index: offset
29
+ } = match;
30
+ const replacePos = tr.mapping.map(position + offset);
31
+ const replacementText = schema.text(SMART_TO_ASCII[smartChar]);
32
+ tr.replaceWith(replacePos, replacePos + smartChar.length, replacementText);
33
+ }
34
+ };
35
+ const isNodeTextBlock = schema => {
36
+ const {
37
+ mention,
38
+ text,
39
+ emoji
40
+ } = schema.nodes;
41
+ return (node, _, parent) => {
42
+ if (node.type === mention || node.type === emoji || node.type === text) {
43
+ return parent === null || parent === void 0 ? void 0 : parent.isTextblock;
44
+ }
45
+ return;
46
+ };
47
+ };
48
+ export const transformSmartCharsMentionsAndEmojis = (from, to, tr) => {
49
+ const {
50
+ schema
51
+ } = tr.doc.type;
52
+ const {
53
+ mention,
54
+ text,
55
+ emoji
56
+ } = schema.nodes;
57
+ // Traverse through all the nodes within the range and replace them with their plaintext counterpart
58
+ const children = filterChildrenBetween(tr.doc, from, to, isNodeTextBlock(schema));
59
+ children.forEach(({
60
+ node,
61
+ pos
62
+ }) => {
63
+ if (node.type === mention || node.type === emoji) {
64
+ replaceMentionOrEmojiForTextContent(pos, node.nodeSize, node.attrs.text, tr);
65
+ } else if (node.type === text && node.text) {
66
+ const replacePosition = pos > from ? pos : from;
67
+ const textToReplace = pos > from ? node.text : node.text.substr(from - pos);
68
+ replaceSmartCharsToAscii(replacePosition, textToReplace, tr);
69
+ }
70
+ });
71
+ };
@@ -0,0 +1 @@
1
+ export { textFormattingPlugin } from './plugin';