@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,124 @@
1
+ import React from 'react';
2
+ import { code, em, strike, strong, subsup, underline } from '@atlaskit/adf-schema';
3
+ import { WithPluginState } from '@atlaskit/editor-common/with-plugin-state';
4
+ import { toggleCodeWithAnalytics, toggleEmWithAnalytics, toggleStrikeWithAnalytics, toggleStrongWithAnalytics, toggleSubscriptWithAnalytics, toggleSuperscriptWithAnalytics, toggleUnderlineWithAnalytics } from './actions';
5
+ import { plugin as clearFormattingPlugin, pluginKey as clearFormattingPluginKey } from './pm-plugins/clear-formatting';
6
+ import clearFormattingKeymapPlugin from './pm-plugins/clear-formatting-keymap';
7
+ import textFormattingCursorPlugin from './pm-plugins/cursor';
8
+ import textFormattingInputRulePlugin from './pm-plugins/input-rule';
9
+ import keymapPlugin from './pm-plugins/keymap';
10
+ import { plugin as pmPlugin, pluginKey as textFormattingPluginKey } from './pm-plugins/main';
11
+ import textFormattingSmartInputRulePlugin from './pm-plugins/smart-input-rule';
12
+ import Toolbar from './ui/Toolbar';
13
+ export const textFormattingPlugin = (options = {}, api) => {
14
+ var _api$dependencies$ana7, _api$dependencies$ana8, _api$dependencies$ana9, _api$dependencies$ana10, _api$dependencies$ana11, _api$dependencies$ana12, _api$dependencies$ana13;
15
+ return {
16
+ name: 'textFormatting',
17
+ marks() {
18
+ return [{
19
+ name: 'em',
20
+ mark: em
21
+ }, {
22
+ name: 'strong',
23
+ mark: strong
24
+ }, {
25
+ name: 'strike',
26
+ mark: strike
27
+ }].concat(options.disableCode ? [] : {
28
+ name: 'code',
29
+ mark: code
30
+ }).concat(options.disableSuperscriptAndSubscript ? [] : {
31
+ name: 'subsup',
32
+ mark: subsup
33
+ }).concat(options.disableUnderline ? [] : {
34
+ name: 'underline',
35
+ mark: underline
36
+ });
37
+ },
38
+ pmPlugins() {
39
+ return [{
40
+ name: 'textFormatting',
41
+ plugin: ({
42
+ dispatch
43
+ }) => {
44
+ var _api$dependencies$ana;
45
+ return pmPlugin(dispatch, api === null || api === void 0 ? void 0 : (_api$dependencies$ana = api.dependencies.analytics) === null || _api$dependencies$ana === void 0 ? void 0 : _api$dependencies$ana.actions);
46
+ }
47
+ }, {
48
+ name: 'textFormattingCursor',
49
+ plugin: () => textFormattingCursorPlugin
50
+ }, {
51
+ name: 'textFormattingInputRule',
52
+ plugin: ({
53
+ schema
54
+ }) => {
55
+ var _api$dependencies$ana2;
56
+ return textFormattingInputRulePlugin(schema, api === null || api === void 0 ? void 0 : (_api$dependencies$ana2 = api.dependencies.analytics) === null || _api$dependencies$ana2 === void 0 ? void 0 : _api$dependencies$ana2.actions);
57
+ }
58
+ }, {
59
+ name: 'textFormattingSmartRule',
60
+ plugin: () => {
61
+ var _api$dependencies$ana3;
62
+ return !options.disableSmartTextCompletion ? textFormattingSmartInputRulePlugin(api === null || api === void 0 ? void 0 : (_api$dependencies$ana3 = api.dependencies.analytics) === null || _api$dependencies$ana3 === void 0 ? void 0 : _api$dependencies$ana3.actions) : undefined;
63
+ }
64
+ }, {
65
+ name: 'textFormattingClear',
66
+ plugin: ({
67
+ dispatch
68
+ }) => clearFormattingPlugin(dispatch)
69
+ }, {
70
+ name: 'textFormattingClearKeymap',
71
+ plugin: () => {
72
+ var _api$dependencies$ana4;
73
+ return clearFormattingKeymapPlugin(api === null || api === void 0 ? void 0 : (_api$dependencies$ana4 = api.dependencies.analytics) === null || _api$dependencies$ana4 === void 0 ? void 0 : _api$dependencies$ana4.actions);
74
+ }
75
+ }, {
76
+ name: 'textFormattingKeymap',
77
+ plugin: ({
78
+ schema
79
+ }) => {
80
+ var _api$dependencies$ana5;
81
+ return keymapPlugin(schema, api === null || api === void 0 ? void 0 : (_api$dependencies$ana5 = api.dependencies.analytics) === null || _api$dependencies$ana5 === void 0 ? void 0 : _api$dependencies$ana5.actions);
82
+ }
83
+ }];
84
+ },
85
+ primaryToolbarComponent({
86
+ editorView,
87
+ popupsMountPoint,
88
+ popupsScrollableElement,
89
+ isToolbarReducedSpacing,
90
+ toolbarSize,
91
+ disabled
92
+ }) {
93
+ return /*#__PURE__*/React.createElement(WithPluginState, {
94
+ plugins: {
95
+ textFormattingState: textFormattingPluginKey,
96
+ clearFormattingPluginState: clearFormattingPluginKey
97
+ },
98
+ render: () => {
99
+ var _api$dependencies$ana6;
100
+ return /*#__PURE__*/React.createElement(Toolbar, {
101
+ editorState: editorView.state,
102
+ popupsMountPoint: popupsMountPoint,
103
+ popupsScrollableElement: popupsScrollableElement,
104
+ toolbarSize: toolbarSize,
105
+ isReducedSpacing: isToolbarReducedSpacing,
106
+ editorView: editorView,
107
+ isToolbarDisabled: disabled,
108
+ shouldUseResponsiveToolbar: Boolean(options.responsiveToolbarMenu),
109
+ editorAnalyticsAPI: api === null || api === void 0 ? void 0 : (_api$dependencies$ana6 = api.dependencies.analytics) === null || _api$dependencies$ana6 === void 0 ? void 0 : _api$dependencies$ana6.actions
110
+ });
111
+ }
112
+ });
113
+ },
114
+ actions: {
115
+ toggleSuperscript: toggleSuperscriptWithAnalytics(api === null || api === void 0 ? void 0 : (_api$dependencies$ana7 = api.dependencies.analytics) === null || _api$dependencies$ana7 === void 0 ? void 0 : _api$dependencies$ana7.actions),
116
+ toggleSubscript: toggleSubscriptWithAnalytics(api === null || api === void 0 ? void 0 : (_api$dependencies$ana8 = api.dependencies.analytics) === null || _api$dependencies$ana8 === void 0 ? void 0 : _api$dependencies$ana8.actions),
117
+ toggleStrike: toggleStrikeWithAnalytics(api === null || api === void 0 ? void 0 : (_api$dependencies$ana9 = api.dependencies.analytics) === null || _api$dependencies$ana9 === void 0 ? void 0 : _api$dependencies$ana9.actions),
118
+ toggleCode: toggleCodeWithAnalytics(api === null || api === void 0 ? void 0 : (_api$dependencies$ana10 = api.dependencies.analytics) === null || _api$dependencies$ana10 === void 0 ? void 0 : _api$dependencies$ana10.actions),
119
+ toggleUnderline: toggleUnderlineWithAnalytics(api === null || api === void 0 ? void 0 : (_api$dependencies$ana11 = api.dependencies.analytics) === null || _api$dependencies$ana11 === void 0 ? void 0 : _api$dependencies$ana11.actions),
120
+ toggleEm: toggleEmWithAnalytics(api === null || api === void 0 ? void 0 : (_api$dependencies$ana12 = api.dependencies.analytics) === null || _api$dependencies$ana12 === void 0 ? void 0 : _api$dependencies$ana12.actions),
121
+ toggleStrong: toggleStrongWithAnalytics(api === null || api === void 0 ? void 0 : (_api$dependencies$ana13 = api.dependencies.analytics) === null || _api$dependencies$ana13 === void 0 ? void 0 : _api$dependencies$ana13.actions)
122
+ }
123
+ };
124
+ };
@@ -0,0 +1,10 @@
1
+ import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
2
+ import * as keymaps from '@atlaskit/editor-common/keymaps';
3
+ import { keymap } from '@atlaskit/editor-prosemirror/keymap';
4
+ import { clearFormattingWithAnalytics } from '../commands/clear-formatting';
5
+ export function keymapPlugin(editorAnalyticsAPI) {
6
+ const list = {};
7
+ keymaps.bindKeymapWithCommand(keymaps.clearFormatting.common, clearFormattingWithAnalytics(INPUT_METHOD.SHORTCUT, editorAnalyticsAPI), list);
8
+ return keymap(list);
9
+ }
10
+ export default keymapPlugin;
@@ -0,0 +1,26 @@
1
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
3
+ import { checkFormattingIsPresent } from '../utils';
4
+ export const pluginKey = new PluginKey('clearFormattingPlugin');
5
+ export const plugin = dispatch => new SafePlugin({
6
+ state: {
7
+ init(_config, state) {
8
+ return {
9
+ formattingIsPresent: checkFormattingIsPresent(state)
10
+ };
11
+ },
12
+ apply(_tr, pluginState, _oldState, newState) {
13
+ const formattingIsPresent = checkFormattingIsPresent(newState);
14
+ if (formattingIsPresent !== pluginState.formattingIsPresent) {
15
+ dispatch(pluginKey, {
16
+ formattingIsPresent
17
+ });
18
+ return {
19
+ formattingIsPresent
20
+ };
21
+ }
22
+ return pluginState;
23
+ }
24
+ },
25
+ key: pluginKey
26
+ });
@@ -0,0 +1,52 @@
1
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
+ import { TextSelection } from '@atlaskit/editor-prosemirror/state';
3
+ export default new SafePlugin({
4
+ props: {
5
+ handleClick(view, clickPos, event) {
6
+ // Don't apply in Edge as per ED-4546
7
+ if (navigator && /Edge\/\d/.test(navigator.userAgent)) {
8
+ return false;
9
+ }
10
+
11
+ // @see ED-6231
12
+ if (clickPos > view.state.doc.content.size) {
13
+ return false;
14
+ }
15
+ const {
16
+ code
17
+ } = view.state.schema.marks;
18
+ const {
19
+ paragraph
20
+ } = view.state.schema.nodes;
21
+ const $click = view.state.doc.resolve(clickPos);
22
+ const clickWasAtEdgeOfATextNode = ($click.nodeBefore ? $click.nodeBefore.isInline : $click.nodeAfter) && ($click.nodeAfter ? $click.nodeAfter.isInline : $click.nodeBefore) && $click.textOffset === 0;
23
+ const clickWasNearACodeMark = code && ($click.nodeBefore && code.isInSet($click.nodeBefore.marks) || $click.nodeAfter && code.isInSet($click.nodeAfter.marks));
24
+
25
+ // Find the starting position of the clicked dom-element
26
+ // TODO: Remove calls to private API
27
+ const clickedDOMElementPosition = event.target && event.target instanceof Node && view.posAtDOM(event.target);
28
+ const clickNode = view.state.doc.nodeAt(clickPos);
29
+ const clickWasAtTextNode = !!(clickNode && clickNode.isText);
30
+ const clickWasAtEndOfAParagraphNode = $click.parent.type === paragraph && $click.textOffset === 0 && $click.nodeAfter === null;
31
+ if (clickWasAtEdgeOfATextNode && clickWasNearACodeMark && clickedDOMElementPosition && (
32
+ // if click did not occur at a text node or end of paragraph, then
33
+ // it was at a directly adjacent non-text node, so we skip this manual
34
+ // text selection logic to preserve that non-text node's selection
35
+ clickWasAtTextNode || clickWasAtEndOfAParagraphNode)) {
36
+ const clickWasInsideNodeDOM = event.target.parentNode === view.domAtPos(clickedDOMElementPosition).node && code.isInSet(view.state.doc.resolve(clickedDOMElementPosition).nodeAfter.marks);
37
+ const nodeNextToClick = $click.nodeBefore && code.isInSet($click.nodeBefore.marks) ? $click.nodeAfter : $click.nodeBefore;
38
+
39
+ // Need to set the selection here to allow clicking between [code('text'),{<>},emoji()]
40
+ const tr = view.state.tr.setSelection(TextSelection.near($click));
41
+ if (clickWasInsideNodeDOM) {
42
+ tr.setStoredMarks([code.create()]);
43
+ } else {
44
+ tr.setStoredMarks(nodeNextToClick ? nodeNextToClick.marks : []);
45
+ }
46
+ view.dispatch(tr);
47
+ return true;
48
+ }
49
+ return false;
50
+ }
51
+ }
52
+ });
@@ -0,0 +1,242 @@
1
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
2
+ import { transformSmartCharsMentionsAndEmojis } from '@atlaskit/editor-common/mark';
3
+ import { inputRuleWithAnalytics } from '@atlaskit/editor-common/utils';
4
+ import { createPlugin, createRule, leafNodeReplacementCharacter } from '@atlaskit/prosemirror-input-rules';
5
+ var ValidAutoformatChars = /*#__PURE__*/function (ValidAutoformatChars) {
6
+ ValidAutoformatChars["STRONG"] = "__";
7
+ ValidAutoformatChars["STRIKE"] = "~~";
8
+ ValidAutoformatChars["STRONG_MARKDOWN"] = "**";
9
+ ValidAutoformatChars["ITALIC_MARKDOWN"] = "*";
10
+ ValidAutoformatChars["ITALIC"] = "_";
11
+ ValidAutoformatChars["CODE"] = "`";
12
+ return ValidAutoformatChars;
13
+ }(ValidAutoformatChars || {});
14
+ export const ValidCombinations = {
15
+ [ValidAutoformatChars.STRIKE]: [
16
+ // e.g: _~~lol~~_
17
+ ValidAutoformatChars.ITALIC,
18
+ // e.g: __~~lol~~__
19
+ ValidAutoformatChars.STRONG,
20
+ // e.g: **~~lol~~**
21
+ ValidAutoformatChars.STRONG_MARKDOWN,
22
+ // e.g: *~~lol~~*
23
+ ValidAutoformatChars.ITALIC_MARKDOWN],
24
+ [ValidAutoformatChars.STRONG]: [
25
+ // e.g: ~~__lol__~~
26
+ ValidAutoformatChars.STRIKE,
27
+ // e.g: *__lol__*
28
+ ValidAutoformatChars.ITALIC_MARKDOWN],
29
+ [ValidAutoformatChars.STRONG_MARKDOWN]: [
30
+ // e.g: _**lol**_
31
+ ValidAutoformatChars.ITALIC,
32
+ // e.g: ~~**lol**~~
33
+ ValidAutoformatChars.STRIKE],
34
+ [ValidAutoformatChars.ITALIC_MARKDOWN]: [
35
+ // e.g: ~~*lol*~~
36
+ ValidAutoformatChars.STRIKE,
37
+ // e.g: __*lol*__
38
+ ValidAutoformatChars.STRONG],
39
+ [ValidAutoformatChars.ITALIC]: [
40
+ // e.g: ~~_lol_~~
41
+ ValidAutoformatChars.STRIKE,
42
+ // e.g: **_lol_**
43
+ ValidAutoformatChars.STRONG_MARKDOWN],
44
+ [ValidAutoformatChars.CODE]: [
45
+ // e.g: loko (`some code`
46
+ '( ']
47
+ };
48
+ function addMark(markType, schema, char) {
49
+ return (state, match, start, end) => {
50
+ var _schema$marks, _schema$marks$code;
51
+ const {
52
+ doc,
53
+ schema,
54
+ tr
55
+ } = state;
56
+ const textPrefix = state.doc.textBetween(start, start + char.length);
57
+
58
+ // fixes the following case: my `*name` is *
59
+ // expected result: should ignore special characters inside "code"
60
+ if (textPrefix !== char || schema !== null && schema !== void 0 && (_schema$marks = schema.marks) !== null && _schema$marks !== void 0 && (_schema$marks$code = _schema$marks.code) !== null && _schema$marks$code !== void 0 && _schema$marks$code.isInSet(doc.resolve(start + 1).marks())) {
61
+ return null;
62
+ }
63
+
64
+ // Prevent autoformatting across hardbreaks
65
+ let containsHardBreak;
66
+ doc.nodesBetween(start, end, node => {
67
+ if (node.type === schema.nodes.hardBreak) {
68
+ containsHardBreak = true;
69
+ return false;
70
+ }
71
+ return !containsHardBreak;
72
+ });
73
+ if (containsHardBreak) {
74
+ return null;
75
+ }
76
+
77
+ // fixes autoformatting in heading nodes: # Heading *bold*
78
+ // expected result: should not autoformat *bold*; <h1>Heading *bold*</h1>
79
+ const startPosResolved = doc.resolve(start);
80
+ const endPosResolved = doc.resolve(end);
81
+ if (startPosResolved.sameParent(endPosResolved) && !startPosResolved.parent.type.allowsMarkType(markType)) {
82
+ return null;
83
+ }
84
+ if (markType.name === 'code') {
85
+ transformSmartCharsMentionsAndEmojis(tr.mapping.map(start), tr.mapping.map(end), tr);
86
+ }
87
+ const mappedStart = tr.mapping.map(start);
88
+ const mappedEnd = tr.mapping.map(end);
89
+ tr.addMark(mappedStart, mappedEnd, markType.create());
90
+ const textSuffix = tr.doc.textBetween(mappedEnd - char.length, mappedEnd);
91
+ if (textSuffix === char) {
92
+ tr.delete(mappedEnd - char.length, mappedEnd);
93
+ }
94
+ if (textPrefix === char) {
95
+ tr.delete(mappedStart, mappedStart + char.length);
96
+ }
97
+ return tr.removeStoredMark(markType);
98
+ };
99
+ }
100
+ class ReverseRegexExp extends RegExp {
101
+ exec(str) {
102
+ if (!str) {
103
+ return null;
104
+ }
105
+ const reverseStr = [...str].reverse().join('');
106
+ const result = super.exec(reverseStr);
107
+ if (!result) {
108
+ return null;
109
+ }
110
+ for (let i = 0; i < result.length; i++) {
111
+ if (result[i] && typeof result[i] === 'string') {
112
+ result[i] = [...result[i]].reverse().join('');
113
+ }
114
+ }
115
+ if (result.input && typeof result.input === 'string') {
116
+ result.input = [...result.input].reverse().join('');
117
+ }
118
+ if (result.input && result[0]) {
119
+ result.index = result.input.length - result[0].length;
120
+ }
121
+ return result;
122
+ }
123
+ }
124
+ const buildRegex = char => {
125
+ const escapedChar = char.replace(/(\W)/g, '\\$1');
126
+ const combinations = ValidCombinations[char].map(c => c.replace(/(\W)/g, '\\$1')).join('|');
127
+
128
+ // Single X - https://regex101.com/r/McT3yq/14/
129
+ // Double X - https://regex101.com/r/pQUgjx/1/
130
+ const baseRegex = '^X(?=[^X\\s]).*?[^\\sX]X(?=[\\sOBJECT_REPLACEMENT_CHARACTER]COMBINATIONS|$)'.replace('OBJECT_REPLACEMENT_CHARACTER', leafNodeReplacementCharacter).replace('COMBINATIONS', combinations ? `|${combinations}` : '');
131
+ const replacedRegex = String.prototype.hasOwnProperty('replaceAll') ? baseRegex.replaceAll('X', escapedChar) : baseRegex.replace(/X/g, escapedChar);
132
+ return new ReverseRegexExp(replacedRegex);
133
+ };
134
+ export const strongRegex1 = buildRegex(ValidAutoformatChars.STRONG);
135
+ export const strongRegex2 = buildRegex(ValidAutoformatChars.STRONG_MARKDOWN);
136
+ export const italicRegex1 = buildRegex(ValidAutoformatChars.ITALIC);
137
+ export const italicRegex2 = buildRegex(ValidAutoformatChars.ITALIC_MARKDOWN);
138
+ export const strikeRegex = buildRegex(ValidAutoformatChars.STRIKE);
139
+ export const codeRegex = buildRegex(ValidAutoformatChars.CODE);
140
+
141
+ /**
142
+ * Create input rules for strong mark
143
+ *
144
+ * @param {Schema} schema
145
+ * @returns {InputRuleWrapper[]}
146
+ */
147
+ function getStrongInputRules(schema, editorAnalyticsAPI) {
148
+ const ruleWithStrongAnalytics = inputRuleWithAnalytics({
149
+ action: ACTION.FORMATTED,
150
+ actionSubject: ACTION_SUBJECT.TEXT,
151
+ actionSubjectId: ACTION_SUBJECT_ID.FORMAT_STRONG,
152
+ eventType: EVENT_TYPE.TRACK,
153
+ attributes: {
154
+ inputMethod: INPUT_METHOD.FORMATTING
155
+ }
156
+ }, editorAnalyticsAPI);
157
+ // **string** or __strong__ should bold the text
158
+ const doubleUnderscoreRule = createRule(strongRegex1, addMark(schema.marks.strong, schema, ValidAutoformatChars.STRONG));
159
+ const doubleAsterixRule = createRule(strongRegex2, addMark(schema.marks.strong, schema, ValidAutoformatChars.STRONG_MARKDOWN));
160
+ return [ruleWithStrongAnalytics(doubleUnderscoreRule), ruleWithStrongAnalytics(doubleAsterixRule)];
161
+ }
162
+
163
+ /**
164
+ * Create input rules for em mark
165
+ *
166
+ * @param {Schema} schema
167
+ * @returns {InputRuleWrapper[]}
168
+ */
169
+ function getItalicInputRules(schema, editorAnalyticsAPI) {
170
+ const ruleWithItalicAnalytics = inputRuleWithAnalytics({
171
+ action: ACTION.FORMATTED,
172
+ actionSubject: ACTION_SUBJECT.TEXT,
173
+ actionSubjectId: ACTION_SUBJECT_ID.FORMAT_ITALIC,
174
+ eventType: EVENT_TYPE.TRACK,
175
+ attributes: {
176
+ inputMethod: INPUT_METHOD.FORMATTING
177
+ }
178
+ }, editorAnalyticsAPI);
179
+ const underscoreRule = createRule(italicRegex1, addMark(schema.marks.em, schema, ValidAutoformatChars.ITALIC));
180
+ const asterixRule = createRule(italicRegex2, addMark(schema.marks.em, schema, ValidAutoformatChars.ITALIC_MARKDOWN));
181
+ return [ruleWithItalicAnalytics(underscoreRule), ruleWithItalicAnalytics(asterixRule)];
182
+ }
183
+
184
+ /**
185
+ * Create input rules for strike mark
186
+ *
187
+ * @param {Schema} schema
188
+ * @returns {InputRuleWrapper[]}
189
+ */
190
+ function getStrikeInputRules(schema, editorAnalyticsAPI) {
191
+ const ruleWithStrikeAnalytics = inputRuleWithAnalytics({
192
+ action: ACTION.FORMATTED,
193
+ actionSubject: ACTION_SUBJECT.TEXT,
194
+ actionSubjectId: ACTION_SUBJECT_ID.FORMAT_STRIKE,
195
+ eventType: EVENT_TYPE.TRACK,
196
+ attributes: {
197
+ inputMethod: INPUT_METHOD.FORMATTING
198
+ }
199
+ }, editorAnalyticsAPI);
200
+ const doubleTildeRule = createRule(strikeRegex, addMark(schema.marks.strike, schema, ValidAutoformatChars.STRIKE));
201
+ return [ruleWithStrikeAnalytics(doubleTildeRule)];
202
+ }
203
+
204
+ /**
205
+ * Create input rules for code mark
206
+ *
207
+ * @param {Schema} schema
208
+ * @returns {InputRuleWrapper[]}
209
+ */
210
+ function getCodeInputRules(schema, editorAnalyticsAPI) {
211
+ const ruleWithCodeAnalytics = inputRuleWithAnalytics({
212
+ action: ACTION.FORMATTED,
213
+ actionSubject: ACTION_SUBJECT.TEXT,
214
+ actionSubjectId: ACTION_SUBJECT_ID.FORMAT_CODE,
215
+ eventType: EVENT_TYPE.TRACK,
216
+ attributes: {
217
+ inputMethod: INPUT_METHOD.FORMATTING
218
+ }
219
+ }, editorAnalyticsAPI);
220
+ const backTickRule = createRule(codeRegex, addMark(schema.marks.code, schema, ValidAutoformatChars.CODE));
221
+ return [ruleWithCodeAnalytics(backTickRule)];
222
+ }
223
+ export function inputRulePlugin(schema, editorAnalyticsAPI) {
224
+ const rules = [];
225
+ if (schema.marks.strong) {
226
+ rules.push(...getStrongInputRules(schema, editorAnalyticsAPI));
227
+ }
228
+ if (schema.marks.em) {
229
+ rules.push(...getItalicInputRules(schema, editorAnalyticsAPI));
230
+ }
231
+ if (schema.marks.strike) {
232
+ rules.push(...getStrikeInputRules(schema, editorAnalyticsAPI));
233
+ }
234
+ if (schema.marks.code) {
235
+ rules.push(...getCodeInputRules(schema, editorAnalyticsAPI));
236
+ }
237
+ if (rules.length !== 0) {
238
+ return createPlugin('text-formatting', rules);
239
+ }
240
+ return;
241
+ }
242
+ export default inputRulePlugin;
@@ -0,0 +1,43 @@
1
+ import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
2
+ import * as keymaps from '@atlaskit/editor-common/keymaps';
3
+ import { keymap } from '@atlaskit/editor-prosemirror/keymap';
4
+ import { toggleCodeWithAnalytics, toggleEmWithAnalytics, toggleStrikeWithAnalytics, toggleStrongWithAnalytics, toggleSubscriptWithAnalytics, toggleSuperscriptWithAnalytics, toggleUnderlineWithAnalytics } from '../actions';
5
+ export default function keymapPlugin(schema, editorAnalyticsAPI) {
6
+ const list = {};
7
+ if (schema.marks.strong) {
8
+ keymaps.bindKeymapWithCommand(keymaps.toggleBold.common, toggleStrongWithAnalytics(editorAnalyticsAPI)({
9
+ inputMethod: INPUT_METHOD.SHORTCUT
10
+ }), list);
11
+ }
12
+ if (schema.marks.em) {
13
+ keymaps.bindKeymapWithCommand(keymaps.toggleItalic.common, toggleEmWithAnalytics(editorAnalyticsAPI)({
14
+ inputMethod: INPUT_METHOD.SHORTCUT
15
+ }), list);
16
+ }
17
+ if (schema.marks.code) {
18
+ keymaps.bindKeymapWithCommand(keymaps.toggleCode.common, toggleCodeWithAnalytics(editorAnalyticsAPI)({
19
+ inputMethod: INPUT_METHOD.SHORTCUT
20
+ }), list);
21
+ }
22
+ if (schema.marks.strike) {
23
+ keymaps.bindKeymapWithCommand(keymaps.toggleStrikethrough.common, toggleStrikeWithAnalytics(editorAnalyticsAPI)({
24
+ inputMethod: INPUT_METHOD.SHORTCUT
25
+ }), list);
26
+ }
27
+ if (schema.marks.subsup) {
28
+ keymaps.bindKeymapWithCommand(keymaps.toggleSubscript.common, toggleSubscriptWithAnalytics(editorAnalyticsAPI)({
29
+ inputMethod: INPUT_METHOD.SHORTCUT
30
+ }), list);
31
+ }
32
+ if (schema.marks.subsup) {
33
+ keymaps.bindKeymapWithCommand(keymaps.toggleSuperscript.common, toggleSuperscriptWithAnalytics(editorAnalyticsAPI)({
34
+ inputMethod: INPUT_METHOD.SHORTCUT
35
+ }), list);
36
+ }
37
+ if (schema.marks.underline) {
38
+ keymaps.bindKeymapWithCommand(keymaps.toggleUnderline.common, toggleUnderlineWithAnalytics(editorAnalyticsAPI)({
39
+ inputMethod: INPUT_METHOD.SHORTCUT
40
+ }), list);
41
+ }
42
+ return keymap(list);
43
+ }
@@ -0,0 +1,110 @@
1
+ // TODO: Ideally this should use the custom toggleMark function from @atlaskit/editor-common so we also disable the options when selecting inline nodes but it disables the marks when the selection is empty at this point in time which is undesirable
2
+ // import { toggleMark } from '@atlaskit/editor-common/mark';
3
+
4
+ import { moveLeft as keymapMoveLeft, moveRight as keymapMoveRight } from '@atlaskit/editor-common/keymaps';
5
+ import { anyMarkActive } from '@atlaskit/editor-common/mark';
6
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
7
+ import { shallowEqual } from '@atlaskit/editor-common/utils';
8
+ import { toggleMark } from '@atlaskit/editor-prosemirror/commands';
9
+ import { createInlineCodeFromTextInputWithAnalytics } from '../commands/text-formatting';
10
+ import * as commands from '../commands/text-formatting';
11
+ import { pluginKey } from './plugin-key';
12
+ export { pluginKey };
13
+ const getTextFormattingState = (editorState, editorAnalyticsAPI) => {
14
+ const {
15
+ em,
16
+ code,
17
+ strike,
18
+ strong,
19
+ subsup,
20
+ underline
21
+ } = editorState.schema.marks;
22
+ const state = {};
23
+ if (code) {
24
+ state.codeActive = anyMarkActive(editorState, code.create());
25
+ state.codeDisabled = !toggleMark(code)(editorState);
26
+ }
27
+ if (em) {
28
+ state.emActive = anyMarkActive(editorState, em);
29
+ state.emDisabled = state.codeActive ? true : !toggleMark(em)(editorState);
30
+ }
31
+ if (strike) {
32
+ state.strikeActive = anyMarkActive(editorState, strike);
33
+ state.strikeDisabled = state.codeActive ? true : !toggleMark(strike)(editorState);
34
+ }
35
+ if (strong) {
36
+ state.strongActive = anyMarkActive(editorState, strong);
37
+ state.strongDisabled = state.codeActive ? true : !toggleMark(strong)(editorState);
38
+ }
39
+ if (subsup) {
40
+ const subMark = subsup.create({
41
+ type: 'sub'
42
+ });
43
+ const supMark = subsup.create({
44
+ type: 'sup'
45
+ });
46
+ state.subscriptActive = anyMarkActive(editorState, subMark);
47
+ state.subscriptDisabled = state.codeActive ? true : !toggleMark(subsup, {
48
+ type: 'sub'
49
+ })(editorState);
50
+ state.superscriptActive = anyMarkActive(editorState, supMark);
51
+ state.superscriptDisabled = state.codeActive ? true : !toggleMark(subsup, {
52
+ type: 'sup'
53
+ })(editorState);
54
+ }
55
+ if (underline) {
56
+ state.underlineActive = anyMarkActive(editorState, underline);
57
+ state.underlineDisabled = state.codeActive ? true : !toggleMark(underline)(editorState);
58
+ }
59
+ return state;
60
+ };
61
+ export const plugin = (dispatch, editorAnalyticsAPI) => new SafePlugin({
62
+ state: {
63
+ init(_config, state) {
64
+ return getTextFormattingState(state, editorAnalyticsAPI);
65
+ },
66
+ apply(_tr, pluginState, _oldState, newState) {
67
+ const state = getTextFormattingState(newState, editorAnalyticsAPI);
68
+ if (!shallowEqual(pluginState, state)) {
69
+ dispatch(pluginKey, state);
70
+ return state;
71
+ }
72
+ return pluginState;
73
+ }
74
+ },
75
+ key: pluginKey,
76
+ props: {
77
+ handleKeyDown(view, event) {
78
+ const {
79
+ state,
80
+ dispatch
81
+ } = view;
82
+ if (event.key === keymapMoveRight.common && !event.metaKey) {
83
+ return commands.moveRight()(state, dispatch);
84
+ } else if (event.key === keymapMoveLeft.common && !event.metaKey) {
85
+ return commands.moveLeft()(state, dispatch);
86
+ }
87
+ return false;
88
+ },
89
+ handleTextInput(view, from, to, text) {
90
+ const {
91
+ state,
92
+ dispatch
93
+ } = view;
94
+ const {
95
+ schema,
96
+ selection: {
97
+ $from: {
98
+ parent: {
99
+ type: parentNodeType
100
+ }
101
+ }
102
+ }
103
+ } = state;
104
+ if (parentNodeType.allowsMarkType(schema.marks.code)) {
105
+ return createInlineCodeFromTextInputWithAnalytics(editorAnalyticsAPI)(from, to, text)(state, dispatch);
106
+ }
107
+ return false;
108
+ }
109
+ }
110
+ });
@@ -0,0 +1,2 @@
1
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
2
+ export const pluginKey = new PluginKey('textFormatting');