@atlaskit/editor-plugin-list 0.2.0 → 1.0.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 (181) hide show
  1. package/.eslintrc.js +14 -0
  2. package/CHANGELOG.md +10 -0
  3. package/README.md +1 -1
  4. package/dist/cjs/actions/conversions.js +153 -0
  5. package/dist/cjs/actions/indent-list-items-selected.js +125 -0
  6. package/dist/cjs/actions/indent-list.js +49 -0
  7. package/dist/cjs/actions/join-list-items-forward.js +59 -0
  8. package/dist/cjs/actions/join-list-items-scenarios/index.js +40 -0
  9. package/dist/cjs/actions/join-list-items-scenarios/join-list-item-with-paragraph.js +88 -0
  10. package/dist/cjs/actions/join-list-items-scenarios/join-list-item-with-parent-nested-list.js +85 -0
  11. package/dist/cjs/actions/join-list-items-scenarios/join-nested-list-with-parent-list-item.js +79 -0
  12. package/dist/cjs/actions/join-list-items-scenarios/join-paragraph-with-list.js +45 -0
  13. package/dist/cjs/actions/join-list-items-scenarios/join-sibling-list-items.js +56 -0
  14. package/dist/cjs/actions/merge-lists.js +27 -0
  15. package/dist/cjs/actions/outdent-list-items-selected.js +291 -0
  16. package/dist/cjs/actions/wrap-and-join-lists.js +100 -0
  17. package/dist/cjs/commands/indent-list.js +71 -0
  18. package/dist/cjs/commands/index.js +350 -0
  19. package/dist/cjs/commands/isFirstChildOfParent.js +12 -0
  20. package/dist/cjs/commands/join-list-item-forward.js +61 -0
  21. package/dist/cjs/commands/listBackspace.js +284 -0
  22. package/dist/cjs/commands/outdent-list.js +70 -0
  23. package/dist/cjs/index.js +8 -1
  24. package/dist/cjs/messages.js +37 -0
  25. package/dist/cjs/plugin.js +133 -0
  26. package/dist/cjs/pm-plugins/input-rules/create-list-input-rule.js +63 -0
  27. package/dist/cjs/pm-plugins/input-rules/index.js +38 -0
  28. package/dist/cjs/pm-plugins/input-rules/wrapping-join-rule.js +60 -0
  29. package/dist/cjs/pm-plugins/keymap.js +27 -0
  30. package/dist/cjs/pm-plugins/main.js +166 -0
  31. package/dist/cjs/transforms.js +99 -0
  32. package/dist/cjs/types.js +4 -1
  33. package/dist/cjs/utils/analytics.js +22 -0
  34. package/dist/cjs/utils/find.js +68 -0
  35. package/dist/cjs/utils/indentation.js +22 -0
  36. package/dist/cjs/utils/mark.js +40 -0
  37. package/dist/cjs/utils/node.js +16 -0
  38. package/dist/cjs/utils/selection.js +95 -0
  39. package/dist/es2019/actions/conversions.js +160 -0
  40. package/dist/es2019/actions/indent-list-items-selected.js +124 -0
  41. package/dist/es2019/actions/indent-list.js +44 -0
  42. package/dist/es2019/actions/join-list-items-forward.js +54 -0
  43. package/dist/es2019/actions/join-list-items-scenarios/index.js +5 -0
  44. package/dist/es2019/actions/join-list-items-scenarios/join-list-item-with-paragraph.js +74 -0
  45. package/dist/es2019/actions/join-list-items-scenarios/join-list-item-with-parent-nested-list.js +77 -0
  46. package/dist/es2019/actions/join-list-items-scenarios/join-nested-list-with-parent-list-item.js +71 -0
  47. package/dist/es2019/actions/join-list-items-scenarios/join-paragraph-with-list.js +37 -0
  48. package/dist/es2019/actions/join-list-items-scenarios/join-sibling-list-items.js +48 -0
  49. package/dist/es2019/actions/merge-lists.js +24 -0
  50. package/dist/es2019/actions/outdent-list-items-selected.js +295 -0
  51. package/dist/es2019/actions/wrap-and-join-lists.js +93 -0
  52. package/dist/es2019/commands/indent-list.js +62 -0
  53. package/dist/es2019/commands/index.js +326 -0
  54. package/dist/es2019/commands/isFirstChildOfParent.js +7 -0
  55. package/dist/es2019/commands/join-list-item-forward.js +53 -0
  56. package/dist/es2019/commands/listBackspace.js +276 -0
  57. package/dist/es2019/commands/outdent-list.js +60 -0
  58. package/dist/es2019/index.js +1 -1
  59. package/dist/es2019/messages.js +29 -0
  60. package/dist/es2019/plugin.js +121 -0
  61. package/dist/es2019/pm-plugins/input-rules/create-list-input-rule.js +56 -0
  62. package/dist/es2019/pm-plugins/input-rules/index.js +35 -0
  63. package/dist/es2019/pm-plugins/input-rules/wrapping-join-rule.js +55 -0
  64. package/dist/es2019/pm-plugins/keymap.js +19 -0
  65. package/dist/es2019/pm-plugins/main.js +156 -0
  66. package/dist/es2019/transforms.js +101 -0
  67. package/dist/es2019/types.js +1 -1
  68. package/dist/es2019/utils/analytics.js +12 -0
  69. package/dist/es2019/utils/find.js +61 -0
  70. package/dist/es2019/utils/indentation.js +15 -0
  71. package/dist/es2019/utils/mark.js +30 -0
  72. package/dist/es2019/utils/node.js +12 -0
  73. package/dist/es2019/utils/selection.js +96 -0
  74. package/dist/esm/actions/conversions.js +147 -0
  75. package/dist/esm/actions/indent-list-items-selected.js +117 -0
  76. package/dist/esm/actions/indent-list.js +43 -0
  77. package/dist/esm/actions/join-list-items-forward.js +52 -0
  78. package/dist/esm/actions/join-list-items-scenarios/index.js +5 -0
  79. package/dist/esm/actions/join-list-items-scenarios/join-list-item-with-paragraph.js +81 -0
  80. package/dist/esm/actions/join-list-items-scenarios/join-list-item-with-parent-nested-list.js +78 -0
  81. package/dist/esm/actions/join-list-items-scenarios/join-nested-list-with-parent-list-item.js +72 -0
  82. package/dist/esm/actions/join-list-items-scenarios/join-paragraph-with-list.js +38 -0
  83. package/dist/esm/actions/join-list-items-scenarios/join-sibling-list-items.js +49 -0
  84. package/dist/esm/actions/merge-lists.js +21 -0
  85. package/dist/esm/actions/outdent-list-items-selected.js +283 -0
  86. package/dist/esm/actions/wrap-and-join-lists.js +94 -0
  87. package/dist/esm/commands/indent-list.js +63 -0
  88. package/dist/esm/commands/index.js +324 -0
  89. package/dist/esm/commands/isFirstChildOfParent.js +5 -0
  90. package/dist/esm/commands/join-list-item-forward.js +53 -0
  91. package/dist/esm/commands/listBackspace.js +275 -0
  92. package/dist/esm/commands/outdent-list.js +62 -0
  93. package/dist/esm/index.js +1 -1
  94. package/dist/esm/messages.js +29 -0
  95. package/dist/esm/plugin.js +126 -0
  96. package/dist/esm/pm-plugins/input-rules/create-list-input-rule.js +57 -0
  97. package/dist/esm/pm-plugins/input-rules/index.js +32 -0
  98. package/dist/esm/pm-plugins/input-rules/wrapping-join-rule.js +54 -0
  99. package/dist/esm/pm-plugins/keymap.js +19 -0
  100. package/dist/esm/pm-plugins/main.js +156 -0
  101. package/dist/esm/transforms.js +91 -0
  102. package/dist/esm/types.js +1 -1
  103. package/dist/esm/utils/analytics.js +12 -0
  104. package/dist/esm/utils/find.js +59 -0
  105. package/dist/esm/utils/indentation.js +15 -0
  106. package/dist/esm/utils/mark.js +33 -0
  107. package/dist/esm/utils/node.js +10 -0
  108. package/dist/esm/utils/selection.js +81 -0
  109. package/dist/types/actions/conversions.d.ts +6 -0
  110. package/dist/types/actions/indent-list-items-selected.d.ts +2 -0
  111. package/dist/types/actions/indent-list.d.ts +2 -0
  112. package/dist/types/actions/join-list-items-forward.d.ts +13 -0
  113. package/dist/types/actions/join-list-items-scenarios/index.d.ts +5 -0
  114. package/dist/types/actions/join-list-items-scenarios/join-list-item-with-paragraph.d.ts +9 -0
  115. package/dist/types/actions/join-list-items-scenarios/join-list-item-with-parent-nested-list.d.ts +9 -0
  116. package/dist/types/actions/join-list-items-scenarios/join-nested-list-with-parent-list-item.d.ts +9 -0
  117. package/dist/types/actions/join-list-items-scenarios/join-paragraph-with-list.d.ts +9 -0
  118. package/dist/types/actions/join-list-items-scenarios/join-sibling-list-items.d.ts +9 -0
  119. package/dist/types/actions/merge-lists.d.ts +7 -0
  120. package/dist/types/actions/outdent-list-items-selected.d.ts +3 -0
  121. package/dist/types/actions/wrap-and-join-lists.d.ts +17 -0
  122. package/dist/types/commands/indent-list.d.ts +6 -0
  123. package/dist/types/commands/index.d.ts +16 -0
  124. package/dist/types/commands/isFirstChildOfParent.d.ts +2 -0
  125. package/dist/types/commands/join-list-item-forward.d.ts +3 -0
  126. package/dist/types/commands/listBackspace.d.ts +10 -0
  127. package/dist/types/commands/outdent-list.d.ts +6 -0
  128. package/dist/types/index.d.ts +2 -1
  129. package/dist/types/messages.d.ts +27 -0
  130. package/dist/types/plugin.d.ts +2 -0
  131. package/dist/types/pm-plugins/input-rules/create-list-input-rule.d.ts +11 -0
  132. package/dist/types/pm-plugins/input-rules/index.d.ts +5 -0
  133. package/dist/types/pm-plugins/input-rules/wrapping-join-rule.d.ts +13 -0
  134. package/dist/types/pm-plugins/keymap.d.ts +5 -0
  135. package/dist/types/pm-plugins/main.d.ts +11 -0
  136. package/dist/types/transforms.d.ts +4 -0
  137. package/dist/types/types.d.ts +4 -6
  138. package/dist/types/utils/analytics.d.ts +5 -0
  139. package/dist/types/utils/find.d.ts +10 -0
  140. package/dist/types/utils/indentation.d.ts +2 -0
  141. package/dist/types/utils/mark.d.ts +8 -0
  142. package/dist/types/utils/node.d.ts +2 -0
  143. package/dist/types/utils/selection.d.ts +14 -0
  144. package/dist/types-ts4.5/actions/conversions.d.ts +6 -0
  145. package/dist/types-ts4.5/actions/indent-list-items-selected.d.ts +2 -0
  146. package/dist/types-ts4.5/actions/indent-list.d.ts +2 -0
  147. package/dist/types-ts4.5/actions/join-list-items-forward.d.ts +16 -0
  148. package/dist/types-ts4.5/actions/join-list-items-scenarios/index.d.ts +5 -0
  149. package/dist/types-ts4.5/actions/join-list-items-scenarios/join-list-item-with-paragraph.d.ts +9 -0
  150. package/dist/types-ts4.5/actions/join-list-items-scenarios/join-list-item-with-parent-nested-list.d.ts +9 -0
  151. package/dist/types-ts4.5/actions/join-list-items-scenarios/join-nested-list-with-parent-list-item.d.ts +9 -0
  152. package/dist/types-ts4.5/actions/join-list-items-scenarios/join-paragraph-with-list.d.ts +9 -0
  153. package/dist/types-ts4.5/actions/join-list-items-scenarios/join-sibling-list-items.d.ts +9 -0
  154. package/dist/types-ts4.5/actions/merge-lists.d.ts +7 -0
  155. package/dist/types-ts4.5/actions/outdent-list-items-selected.d.ts +3 -0
  156. package/dist/types-ts4.5/actions/wrap-and-join-lists.d.ts +17 -0
  157. package/dist/types-ts4.5/commands/indent-list.d.ts +6 -0
  158. package/dist/types-ts4.5/commands/index.d.ts +16 -0
  159. package/dist/types-ts4.5/commands/isFirstChildOfParent.d.ts +2 -0
  160. package/dist/types-ts4.5/commands/join-list-item-forward.d.ts +3 -0
  161. package/dist/types-ts4.5/commands/listBackspace.d.ts +13 -0
  162. package/dist/types-ts4.5/commands/outdent-list.d.ts +6 -0
  163. package/dist/types-ts4.5/index.d.ts +2 -1
  164. package/dist/types-ts4.5/messages.d.ts +27 -0
  165. package/dist/types-ts4.5/plugin.d.ts +2 -0
  166. package/dist/types-ts4.5/pm-plugins/input-rules/create-list-input-rule.d.ts +11 -0
  167. package/dist/types-ts4.5/pm-plugins/input-rules/index.d.ts +5 -0
  168. package/dist/types-ts4.5/pm-plugins/input-rules/wrapping-join-rule.d.ts +13 -0
  169. package/dist/types-ts4.5/pm-plugins/keymap.d.ts +5 -0
  170. package/dist/types-ts4.5/pm-plugins/main.d.ts +11 -0
  171. package/dist/types-ts4.5/transforms.d.ts +4 -0
  172. package/dist/types-ts4.5/types.d.ts +4 -6
  173. package/dist/types-ts4.5/utils/analytics.d.ts +5 -0
  174. package/dist/types-ts4.5/utils/find.d.ts +10 -0
  175. package/dist/types-ts4.5/utils/indentation.d.ts +2 -0
  176. package/dist/types-ts4.5/utils/mark.d.ts +8 -0
  177. package/dist/types-ts4.5/utils/node.d.ts +2 -0
  178. package/dist/types-ts4.5/utils/selection.d.ts +14 -0
  179. package/package.json +8 -5
  180. package/report.api.md +6 -2
  181. package/tmp/api-report-tmp.d.ts +4 -1
@@ -0,0 +1,60 @@
1
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD, OUTDENT_SCENARIOS } from '@atlaskit/editor-common/analytics';
2
+ import { getCommonListAnalyticsAttributes } from '@atlaskit/editor-common/lists';
3
+ import { isBulletList } from '@atlaskit/editor-common/utils';
4
+ import { closeHistory } from '@atlaskit/editor-prosemirror/history';
5
+ import { outdentListItemsSelected as outdentListAction } from '../actions/outdent-list-items-selected';
6
+ import { getRestartListsAttributes } from '../utils/analytics';
7
+ import { findFirstParentListNode } from '../utils/find';
8
+ import { isInsideListItem, isInsideTableCell } from '../utils/selection';
9
+ export const outdentList = editorAnalyticsAPI => (inputMethod = INPUT_METHOD.KEYBOARD, featureFlags) => {
10
+ return function (state, dispatch) {
11
+ if (!isInsideListItem(state)) {
12
+ return false;
13
+ }
14
+ const {
15
+ $from
16
+ } = state.selection;
17
+ const parentListNode = findFirstParentListNode($from);
18
+ if (!parentListNode) {
19
+ // Even though this is a non-operation, we don't want to send this event to the browser. Because if we return false, the browser will move the focus to another place
20
+ return true;
21
+ }
22
+
23
+ // Save the history, so it could undo/revert to the same state before the outdent, see https://product-fabric.atlassian.net/browse/ED-14753
24
+ closeHistory(state.tr);
25
+ const actionSubjectId = isBulletList(parentListNode.node) ? ACTION_SUBJECT_ID.FORMAT_LIST_BULLET : ACTION_SUBJECT_ID.FORMAT_LIST_NUMBER;
26
+ let customTr = state.tr;
27
+ outdentListAction(customTr, state, featureFlags);
28
+ if (!customTr || !customTr.docChanged) {
29
+ // Even though this is a non-operation, we don't want to send this event to the browser. Because if we return false, the browser will move the focus to another place
30
+ // If inside table cell and can't outdent list, then let it handle by table keymap
31
+ return !isInsideTableCell(state);
32
+ }
33
+ const restartListsAttributes = {};
34
+ if (featureFlags !== null && featureFlags !== void 0 && featureFlags.restartNumberedLists) {
35
+ const {
36
+ outdentScenario,
37
+ splitListStartNumber
38
+ } = getRestartListsAttributes(customTr);
39
+ if (outdentScenario === OUTDENT_SCENARIOS.SPLIT_LIST) {
40
+ restartListsAttributes.outdentScenario = outdentScenario;
41
+ restartListsAttributes.splitListStartNumber = splitListStartNumber;
42
+ }
43
+ }
44
+ editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent({
45
+ action: ACTION.OUTDENTED,
46
+ actionSubject: ACTION_SUBJECT.LIST,
47
+ actionSubjectId,
48
+ eventType: EVENT_TYPE.TRACK,
49
+ attributes: {
50
+ ...getCommonListAnalyticsAttributes(state),
51
+ ...restartListsAttributes,
52
+ inputMethod
53
+ }
54
+ })(customTr);
55
+ if (dispatch) {
56
+ dispatch(customTr);
57
+ }
58
+ return true;
59
+ };
60
+ };
@@ -1 +1 @@
1
- export {};
1
+ export { listPlugin } from './plugin';
@@ -0,0 +1,29 @@
1
+ // Common Translations will live here
2
+ import { defineMessages } from 'react-intl-next';
3
+ export const messages = defineMessages({
4
+ unorderedList: {
5
+ id: 'fabric.editor.unorderedList',
6
+ defaultMessage: 'Bullet list',
7
+ description: 'A list with bullets. Also known as an “unordered” list'
8
+ },
9
+ unorderedListDescription: {
10
+ id: 'fabric.editor.unorderedList.description',
11
+ defaultMessage: 'Create an unordered list',
12
+ description: ''
13
+ },
14
+ orderedList: {
15
+ id: 'fabric.editor.orderedList',
16
+ defaultMessage: 'Numbered list',
17
+ description: 'A list with ordered items 1… 2… 3…'
18
+ },
19
+ orderedListDescription: {
20
+ id: 'fabric.editor.orderedList.description',
21
+ defaultMessage: 'Create an ordered list',
22
+ description: ''
23
+ },
24
+ lists: {
25
+ id: 'fabric.editor.lists',
26
+ defaultMessage: 'Lists',
27
+ description: 'Menu shows ordered/bullet list and unordered/numbered lists'
28
+ }
29
+ });
@@ -0,0 +1,121 @@
1
+ import React from 'react';
2
+ import { bulletList, listItem, orderedList, orderedListWithOrder } from '@atlaskit/adf-schema';
3
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
4
+ import { toggleBulletList, toggleOrderedList, tooltip } from '@atlaskit/editor-common/keymaps';
5
+ import { listMessages as messages } from '@atlaskit/editor-common/messages';
6
+ import { IconList, IconListNumber } from '@atlaskit/editor-common/quick-insert';
7
+ import { indentList, outdentList, toggleBulletList as toggleBulletListCommand, toggleOrderedList as toggleOrderedListCommand } from './commands';
8
+ import inputRulePlugin from './pm-plugins/input-rules';
9
+ import keymapPlugin from './pm-plugins/keymap';
10
+ import { createPlugin, pluginKey as listPluginKey } from './pm-plugins/main';
11
+ import { findRootParentListNode } from './utils/find';
12
+ import { isInsideListItem } from './utils/selection';
13
+
14
+ /*
15
+ Toolbar buttons to bullet and ordered list can be found in
16
+ packages/editor/editor-core/src/plugins/toolbar-lists-indentation/ui/Toolbar.tsx
17
+ */
18
+ export const listPlugin = (options, api) => {
19
+ var _api$dependencies$ana;
20
+ const featureFlags = (api === null || api === void 0 ? void 0 : api.dependencies.featureFlags.sharedState.currentState()) || {};
21
+ const editorAnalyticsAPI = 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;
22
+ return {
23
+ name: 'list',
24
+ actions: {
25
+ indentList: indentList(editorAnalyticsAPI),
26
+ outdentList: outdentList(editorAnalyticsAPI),
27
+ toggleOrderedList: toggleOrderedListCommand(editorAnalyticsAPI),
28
+ toggleBulletList: toggleBulletListCommand(editorAnalyticsAPI),
29
+ isInsideListItem,
30
+ findRootParentListNode
31
+ },
32
+ getSharedState: editorState => {
33
+ if (!editorState) {
34
+ return undefined;
35
+ }
36
+ return listPluginKey.getState(editorState);
37
+ },
38
+ nodes() {
39
+ return [{
40
+ name: 'bulletList',
41
+ node: bulletList
42
+ }, {
43
+ name: 'orderedList',
44
+ node: options !== null && options !== void 0 && options.restartNumberedLists ? orderedListWithOrder : orderedList
45
+ }, {
46
+ name: 'listItem',
47
+ node: listItem
48
+ }];
49
+ },
50
+ pmPlugins() {
51
+ return [{
52
+ name: 'list',
53
+ plugin: ({
54
+ dispatch
55
+ }) => createPlugin(dispatch, featureFlags)
56
+ }, {
57
+ name: 'listInputRule',
58
+ plugin: ({
59
+ schema,
60
+ featureFlags
61
+ }) => {
62
+ var _api$dependencies$ana2;
63
+ return inputRulePlugin(schema, featureFlags, 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);
64
+ }
65
+ }, {
66
+ name: 'listKeymap',
67
+ plugin: () => {
68
+ var _api$dependencies$ana3;
69
+ return keymapPlugin(featureFlags, 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);
70
+ }
71
+ }];
72
+ },
73
+ pluginsOptions: {
74
+ quickInsert: ({
75
+ formatMessage
76
+ }) => [{
77
+ id: 'unorderedList',
78
+ title: formatMessage(messages.unorderedList),
79
+ description: formatMessage(messages.unorderedListDescription),
80
+ keywords: ['ul', 'unordered'],
81
+ priority: 1100,
82
+ keyshortcut: tooltip(toggleBulletList),
83
+ icon: () => /*#__PURE__*/React.createElement(IconList, null),
84
+ action(insert, state) {
85
+ const tr = insert(state.schema.nodes.bulletList.createChecked({}, state.schema.nodes.listItem.createChecked({}, state.schema.nodes.paragraph.createChecked())));
86
+ editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent({
87
+ action: ACTION.INSERTED,
88
+ actionSubject: ACTION_SUBJECT.LIST,
89
+ actionSubjectId: ACTION_SUBJECT_ID.FORMAT_LIST_BULLET,
90
+ eventType: EVENT_TYPE.TRACK,
91
+ attributes: {
92
+ inputMethod: INPUT_METHOD.QUICK_INSERT
93
+ }
94
+ })(tr);
95
+ return tr;
96
+ }
97
+ }, {
98
+ id: 'orderedList',
99
+ title: formatMessage(messages.orderedList),
100
+ description: formatMessage(messages.orderedListDescription),
101
+ keywords: ['ol', 'ordered'],
102
+ priority: 1200,
103
+ keyshortcut: tooltip(toggleOrderedList),
104
+ icon: () => /*#__PURE__*/React.createElement(IconListNumber, null),
105
+ action(insert, state) {
106
+ const tr = insert(state.schema.nodes.orderedList.createChecked({}, state.schema.nodes.listItem.createChecked({}, state.schema.nodes.paragraph.createChecked())));
107
+ editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent({
108
+ action: ACTION.INSERTED,
109
+ actionSubject: ACTION_SUBJECT.LIST,
110
+ actionSubjectId: ACTION_SUBJECT_ID.FORMAT_LIST_NUMBER,
111
+ eventType: EVENT_TYPE.TRACK,
112
+ attributes: {
113
+ inputMethod: INPUT_METHOD.QUICK_INSERT
114
+ }
115
+ })(tr);
116
+ return tr;
117
+ }
118
+ }]
119
+ }
120
+ };
121
+ };
@@ -0,0 +1,56 @@
1
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD, JOIN_SCENARIOS_WHEN_TYPING_TO_INSERT_LIST } from '@atlaskit/editor-common/analytics';
2
+ import { inputRuleWithAnalytics as ruleWithAnalytics } from '@atlaskit/editor-common/utils';
3
+ import { createWrappingJoinRule } from './wrapping-join-rule';
4
+ const getOrder = matchResult => Number(matchResult[1]);
5
+ export function createRuleForListType({
6
+ listType,
7
+ expression,
8
+ featureFlags,
9
+ editorAnalyticsApi
10
+ }) {
11
+ let joinScenario = JOIN_SCENARIOS_WHEN_TYPING_TO_INSERT_LIST.NO_JOIN;
12
+ const isBulletList = listType.name === 'bulletList';
13
+ const actionSubjectId = isBulletList ? ACTION_SUBJECT_ID.FORMAT_LIST_BULLET : ACTION_SUBJECT_ID.FORMAT_LIST_NUMBER;
14
+ const getAnalyticsPayload = (state, matchResult) => {
15
+ const analyticsPayload = {
16
+ action: ACTION.INSERTED,
17
+ actionSubject: ACTION_SUBJECT.LIST,
18
+ actionSubjectId,
19
+ eventType: EVENT_TYPE.TRACK,
20
+ attributes: {
21
+ inputMethod: INPUT_METHOD.FORMATTING
22
+ }
23
+ };
24
+ if (featureFlags !== null && featureFlags !== void 0 && featureFlags.restartNumberedLists && listType === state.schema.nodes.orderedList && analyticsPayload.attributes) {
25
+ analyticsPayload.attributes.listStartNumber = getOrder(matchResult);
26
+ analyticsPayload.attributes.joinScenario = joinScenario;
27
+ // we reset the tracked joinScenario after storing it in the event payload
28
+ joinScenario = JOIN_SCENARIOS_WHEN_TYPING_TO_INSERT_LIST.NO_JOIN;
29
+ }
30
+ return analyticsPayload;
31
+ };
32
+ const joinToNeighbourIfSameListType = (_, node, scenario) => {
33
+ const shouldJoin = node.type === listType;
34
+ if (shouldJoin) {
35
+ joinScenario = scenario;
36
+ }
37
+ return shouldJoin;
38
+ };
39
+ let getAttrs = {};
40
+ if (featureFlags !== null && featureFlags !== void 0 && featureFlags.restartNumberedLists) {
41
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
+ getAttrs = matchResult => {
43
+ return {
44
+ order: getOrder(matchResult)
45
+ };
46
+ };
47
+ }
48
+ const inputRule = createWrappingJoinRule({
49
+ featureFlags,
50
+ match: expression,
51
+ nodeType: listType,
52
+ getAttrs,
53
+ joinPredicate: joinToNeighbourIfSameListType
54
+ });
55
+ return ruleWithAnalytics(getAnalyticsPayload, editorAnalyticsApi)(inputRule);
56
+ }
@@ -0,0 +1,35 @@
1
+ import { createPlugin } from '@atlaskit/prosemirror-input-rules';
2
+ import { createRuleForListType } from './create-list-input-rule';
3
+ export default function inputRulePlugin(schema, featureFlags, editorAnalyticsApi) {
4
+ const {
5
+ nodes: {
6
+ bulletList,
7
+ orderedList
8
+ }
9
+ } = schema;
10
+ const rules = [];
11
+ if (bulletList) {
12
+ rules.push(createRuleForListType({
13
+ // Using UTF instead of • character
14
+ // because of issue where product converted the
15
+ // character into an escaped version.
16
+ expression: /^\s*([\*\-\u2022]) $/,
17
+ listType: bulletList,
18
+ featureFlags,
19
+ editorAnalyticsApi
20
+ }));
21
+ }
22
+ const expression = featureFlags !== null && featureFlags !== void 0 && featureFlags.restartNumberedLists ? /((^[1-9]{1}[0-9]{0,2})|^(0))[\.\)] $/ : /^(1)[\.\)] $/;
23
+ if (orderedList) {
24
+ rules.push(createRuleForListType({
25
+ expression,
26
+ listType: orderedList,
27
+ featureFlags,
28
+ editorAnalyticsApi
29
+ }));
30
+ }
31
+ if (rules.length !== 0) {
32
+ return createPlugin('lists', rules);
33
+ }
34
+ return;
35
+ }
@@ -0,0 +1,55 @@
1
+ import { JOIN_SCENARIOS_WHEN_TYPING_TO_INSERT_LIST } from '@atlaskit/editor-common/analytics';
2
+ import { canJoin, findWrapping } from '@atlaskit/editor-prosemirror/transform';
3
+ import { findParentNodeOfTypeClosestToPos } from '@atlaskit/editor-prosemirror/utils';
4
+ import { createRule } from '@atlaskit/prosemirror-input-rules';
5
+
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
+
8
+ export const createWrappingJoinRule = ({
9
+ match,
10
+ nodeType,
11
+ getAttrs,
12
+ joinPredicate,
13
+ featureFlags
14
+ }) => {
15
+ const handler = (state, match, start, end) => {
16
+ const attrs = (getAttrs instanceof Function ? getAttrs(match) : getAttrs) || {};
17
+ const tr = state.tr;
18
+ const fixedStart = Math.max(start, 1);
19
+ tr.delete(fixedStart, end);
20
+ const $start = tr.doc.resolve(fixedStart);
21
+ const range = $start.blockRange();
22
+ const wrapping = range && findWrapping(range, nodeType, attrs);
23
+ if (!wrapping || !range) {
24
+ return null;
25
+ }
26
+ const parentNodePosMapped = tr.mapping.map(range.start);
27
+ const parentNode = tr.doc.nodeAt(parentNodePosMapped);
28
+ const lastWrap = wrapping[wrapping.length - 1];
29
+ if (parentNode && lastWrap) {
30
+ const allowedMarks = lastWrap.type.allowedMarks(parentNode.marks) || [];
31
+ tr.setNodeMarkup(parentNodePosMapped, parentNode.type, parentNode.attrs, allowedMarks);
32
+ }
33
+ tr.wrap(range, wrapping);
34
+ if (featureFlags !== null && featureFlags !== void 0 && featureFlags.restartNumberedLists && nodeType === state.schema.nodes.orderedList) {
35
+ // if an orderedList node would be inserted by the input rule match, and
36
+ // that orderedList node is being added directly before another orderedList
37
+ // node, then join those nodes
38
+ const $end = tr.doc.resolve(tr.mapping.map(end));
39
+ const node = findParentNodeOfTypeClosestToPos($end, nodeType);
40
+ if (node) {
41
+ const nodeEnd = node.pos + node.node.nodeSize;
42
+ const after = tr.doc.resolve(nodeEnd).nodeAfter;
43
+ if (after && after.type === nodeType && canJoin(tr.doc, nodeEnd) && (!joinPredicate || joinPredicate(match, after, JOIN_SCENARIOS_WHEN_TYPING_TO_INSERT_LIST.JOINED_TO_LIST_BELOW))) {
44
+ tr.join(nodeEnd);
45
+ }
46
+ }
47
+ }
48
+ const before = tr.doc.resolve(fixedStart - 1).nodeBefore;
49
+ if (before && before.type === nodeType && canJoin(tr.doc, fixedStart - 1) && (!joinPredicate || joinPredicate(match, before, JOIN_SCENARIOS_WHEN_TYPING_TO_INSERT_LIST.JOINED_TO_LIST_ABOVE))) {
50
+ tr.join(fixedStart - 1);
51
+ }
52
+ return tr;
53
+ };
54
+ return createRule(match, handler);
55
+ };
@@ -0,0 +1,19 @@
1
+ import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
2
+ import { backspace, bindKeymapWithCommand, deleteKey, enter, findKeyMapForBrowser, findShortcutByKeymap, forwardDelete, indentList, outdentList, toggleBulletList, toggleOrderedList } from '@atlaskit/editor-common/keymaps';
3
+ import { keymap } from '@atlaskit/editor-prosemirror/keymap';
4
+ import { backspaceKeyCommand, deleteKeyCommand, enterKeyCommand, indentList as indentListCommand, outdentList as outdentListCommand, toggleList } from '../commands';
5
+ export function keymapPlugin(featureFlags, editorAnalyticsAPI) {
6
+ const list = {};
7
+ bindKeymapWithCommand(findShortcutByKeymap(toggleOrderedList), toggleList(editorAnalyticsAPI)(INPUT_METHOD.KEYBOARD, 'orderedList'), list);
8
+ bindKeymapWithCommand(findShortcutByKeymap(toggleBulletList), toggleList(editorAnalyticsAPI)(INPUT_METHOD.KEYBOARD, 'bulletList'), list);
9
+ bindKeymapWithCommand(indentList.common, indentListCommand(editorAnalyticsAPI)(INPUT_METHOD.KEYBOARD), list);
10
+ bindKeymapWithCommand(outdentList.common, outdentListCommand(editorAnalyticsAPI)(INPUT_METHOD.KEYBOARD, featureFlags), list);
11
+ bindKeymapWithCommand(enter.common, enterKeyCommand(editorAnalyticsAPI)(featureFlags), list);
12
+ bindKeymapWithCommand(backspace.common, backspaceKeyCommand(editorAnalyticsAPI)(featureFlags), list);
13
+ bindKeymapWithCommand(deleteKey.common, deleteKeyCommand(editorAnalyticsAPI), list);
14
+
15
+ // This shortcut is Mac only
16
+ bindKeymapWithCommand(findKeyMapForBrowser(forwardDelete), deleteKeyCommand(editorAnalyticsAPI), list);
17
+ return keymap(list);
18
+ }
19
+ export default keymapPlugin;
@@ -0,0 +1,156 @@
1
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
+ import { setGapCursorSelection, Side } from '@atlaskit/editor-common/selection';
3
+ import { CodeBlockSharedCssClassName, getOrderedListInlineStyles, listItemCounterPadding } from '@atlaskit/editor-common/styles';
4
+ import { getItemCounterDigitsSize, isListNode, pluginFactory } from '@atlaskit/editor-common/utils';
5
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
6
+ import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
7
+ import { Decoration, DecorationSet } from '@atlaskit/editor-prosemirror/view';
8
+ import { isWrappingPossible } from '../utils/selection';
9
+ const listPluginKey = new PluginKey('listPlugin');
10
+ export const pluginKey = listPluginKey;
11
+ const initialState = {
12
+ bulletListActive: false,
13
+ bulletListDisabled: false,
14
+ orderedListActive: false,
15
+ orderedListDisabled: false,
16
+ decorationSet: DecorationSet.empty
17
+ };
18
+ export const getDecorations = (doc, state, featureFlags) => {
19
+ const decorations = [];
20
+
21
+ // this stack keeps track of each (nested) list to calculate the indentation level
22
+ const processedListsStack = [];
23
+ doc.nodesBetween(0, doc.content.size, (node, currentNodeStartPos) => {
24
+ if (processedListsStack.length > 0) {
25
+ let isOutsideLastList = true;
26
+ while (isOutsideLastList && processedListsStack.length > 0) {
27
+ const lastList = processedListsStack[processedListsStack.length - 1];
28
+ const lastListEndPos = lastList.startPos + lastList.node.nodeSize;
29
+ isOutsideLastList = currentNodeStartPos >= lastListEndPos;
30
+ // once we finish iterating over each innermost list, pop the stack to
31
+ // decrease the indent level attribute accordingly
32
+ if (isOutsideLastList) {
33
+ processedListsStack.pop();
34
+ }
35
+ }
36
+ }
37
+ if (isListNode(node)) {
38
+ processedListsStack.push({
39
+ node,
40
+ startPos: currentNodeStartPos
41
+ });
42
+ const from = currentNodeStartPos;
43
+ const to = currentNodeStartPos + node.nodeSize;
44
+ const depth = processedListsStack.length;
45
+ decorations.push(Decoration.node(from, to, {
46
+ 'data-indent-level': `${depth}`
47
+ }));
48
+ if (featureFlags !== null && featureFlags !== void 0 && featureFlags.restartNumberedLists) {
49
+ var _node$attrs;
50
+ // If a numbered list has item counters numbering >= 100, we'll need to add special
51
+ // spacing to account for the extra digit chars
52
+ const digitsSize = getItemCounterDigitsSize({
53
+ itemsCount: node === null || node === void 0 ? void 0 : node.childCount,
54
+ order: node === null || node === void 0 ? void 0 : (_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.order
55
+ });
56
+ if (digitsSize) {
57
+ decorations.push(Decoration.node(from, to, {
58
+ style: getOrderedListInlineStyles(digitsSize, 'string')
59
+ }));
60
+ }
61
+ } else {
62
+ if (node.childCount >= 100) {
63
+ decorations.push(Decoration.node(from, to, {
64
+ 'data-child-count': '100+'
65
+ }));
66
+ }
67
+ }
68
+ }
69
+ });
70
+ return DecorationSet.empty.add(doc, decorations);
71
+ };
72
+ const handleDocChanged = featureFlags => (tr, pluginState, editorState) => {
73
+ const nextPluginState = handleSelectionChanged(tr, pluginState);
74
+ const decorationSet = getDecorations(tr.doc, editorState, featureFlags);
75
+ return {
76
+ ...nextPluginState,
77
+ decorationSet
78
+ };
79
+ };
80
+ const handleSelectionChanged = (tr, pluginState) => {
81
+ const {
82
+ bulletList,
83
+ orderedList
84
+ } = tr.doc.type.schema.nodes;
85
+ const listParent = findParentNodeOfType([bulletList, orderedList])(tr.selection);
86
+ const bulletListActive = !!listParent && listParent.node.type === bulletList;
87
+ const orderedListActive = !!listParent && listParent.node.type === orderedList;
88
+ const bulletListDisabled = !(bulletListActive || orderedListActive || isWrappingPossible(bulletList, tr.selection));
89
+ const orderedListDisabled = !(bulletListActive || orderedListActive || isWrappingPossible(orderedList, tr.selection));
90
+ if (bulletListActive !== pluginState.bulletListActive || orderedListActive !== pluginState.orderedListActive || bulletListDisabled !== pluginState.bulletListDisabled || orderedListDisabled !== pluginState.orderedListDisabled) {
91
+ const nextPluginState = {
92
+ ...pluginState,
93
+ bulletListActive,
94
+ orderedListActive,
95
+ bulletListDisabled,
96
+ orderedListDisabled
97
+ };
98
+ return nextPluginState;
99
+ }
100
+ return pluginState;
101
+ };
102
+ const reducer = () => state => {
103
+ return state;
104
+ };
105
+ const createInitialState = featureFlags => state => {
106
+ return {
107
+ ...initialState,
108
+ decorationSet: getDecorations(state.doc, state, featureFlags)
109
+ };
110
+ };
111
+ export const createPlugin = (eventDispatch, featureFlags) => {
112
+ const {
113
+ getPluginState,
114
+ createPluginState
115
+ } = pluginFactory(listPluginKey, reducer(), {
116
+ onDocChanged: handleDocChanged(featureFlags),
117
+ onSelectionChanged: handleSelectionChanged
118
+ });
119
+ return new SafePlugin({
120
+ state: createPluginState(eventDispatch, createInitialState(featureFlags)),
121
+ key: listPluginKey,
122
+ props: {
123
+ decorations(state) {
124
+ const {
125
+ decorationSet
126
+ } = getPluginState(state);
127
+ return decorationSet;
128
+ },
129
+ handleClick: (view, pos, event) => {
130
+ const {
131
+ state
132
+ } = view;
133
+ if (['LI', 'UL'].includes((event === null || event === void 0 ? void 0 : event.target).tagName)) {
134
+ var _nodeAtPos$firstChild;
135
+ const nodeAtPos = state.tr.doc.nodeAt(pos);
136
+ const {
137
+ listItem,
138
+ codeBlock
139
+ } = view.state.schema.nodes;
140
+ if ((nodeAtPos === null || nodeAtPos === void 0 ? void 0 : nodeAtPos.type) === listItem && (nodeAtPos === null || nodeAtPos === void 0 ? void 0 : (_nodeAtPos$firstChild = nodeAtPos.firstChild) === null || _nodeAtPos$firstChild === void 0 ? void 0 : _nodeAtPos$firstChild.type) === codeBlock) {
141
+ var _document, _document$elementFrom;
142
+ const bufferPx = 50;
143
+ const isCodeBlockNextToListMarker = Boolean((_document = document) === null || _document === void 0 ? void 0 : (_document$elementFrom = _document.elementFromPoint(event.clientX + (listItemCounterPadding + bufferPx), event.clientY)) === null || _document$elementFrom === void 0 ? void 0 : _document$elementFrom.closest(`.${CodeBlockSharedCssClassName.CODEBLOCK_CONTAINER}`));
144
+ if (isCodeBlockNextToListMarker) {
145
+ // +1 needed to put cursor inside li
146
+ // otherwise gap cursor markup will be injected as immediate child of ul resulting in invalid html
147
+ setGapCursorSelection(view, pos + 1, Side.LEFT);
148
+ return true;
149
+ }
150
+ }
151
+ }
152
+ return false;
153
+ }
154
+ }
155
+ });
156
+ };
@@ -0,0 +1,101 @@
1
+ import { Fragment, NodeRange, Slice } from '@atlaskit/editor-prosemirror/model';
2
+ import { TextSelection } from '@atlaskit/editor-prosemirror/state';
3
+ import { liftTarget, ReplaceAroundStep } from '@atlaskit/editor-prosemirror/transform';
4
+ import { getListLiftTarget } from './utils/indentation';
5
+ function liftListItem(selection, tr) {
6
+ let {
7
+ $from,
8
+ $to
9
+ } = selection;
10
+ const nodeType = tr.doc.type.schema.nodes.listItem;
11
+ let range = $from.blockRange($to, node => !!node.childCount && !!node.firstChild && node.firstChild.type === nodeType);
12
+ if (!range || range.depth < 2 || $from.node(range.depth - 1).type !== nodeType) {
13
+ return tr;
14
+ }
15
+ let end = range.end;
16
+ let endOfList = $to.end(range.depth);
17
+ if (end < endOfList) {
18
+ tr.step(new ReplaceAroundStep(end - 1, endOfList, end, endOfList, new Slice(Fragment.from(nodeType.create(undefined, range.parent.copy())), 1, 0), 1, true));
19
+ range = new NodeRange(tr.doc.resolve($from.pos), tr.doc.resolve(endOfList), range.depth);
20
+ }
21
+ return tr.lift(range, liftTarget(range)).scrollIntoView();
22
+ }
23
+
24
+ // Function will lift list item following selection to level-1.
25
+ export function liftFollowingList(from, to, rootListDepth, tr) {
26
+ const {
27
+ listItem
28
+ } = tr.doc.type.schema.nodes;
29
+ let lifted = false;
30
+ tr.doc.nodesBetween(from, to, (node, pos) => {
31
+ if (!lifted && node.type === listItem && pos > from) {
32
+ lifted = true;
33
+ let listDepth = rootListDepth + 3;
34
+ while (listDepth > rootListDepth + 2) {
35
+ const start = tr.doc.resolve(tr.mapping.map(pos));
36
+ listDepth = start.depth;
37
+ const end = tr.doc.resolve(tr.mapping.map(pos + node.textContent.length));
38
+ const sel = new TextSelection(start, end);
39
+ tr = liftListItem(sel, tr);
40
+ }
41
+ }
42
+ });
43
+ return tr;
44
+ }
45
+ export function liftNodeSelectionList(selection, tr) {
46
+ const {
47
+ from
48
+ } = selection;
49
+ const {
50
+ listItem
51
+ } = tr.doc.type.schema.nodes;
52
+ const mappedPosition = tr.mapping.map(from);
53
+ const nodeAtPos = tr.doc.nodeAt(mappedPosition);
54
+ const start = tr.doc.resolve(mappedPosition);
55
+ if ((start === null || start === void 0 ? void 0 : start.parent.type) !== listItem) {
56
+ return tr;
57
+ }
58
+ const end = tr.doc.resolve(mappedPosition + ((nodeAtPos === null || nodeAtPos === void 0 ? void 0 : nodeAtPos.nodeSize) || 1));
59
+ const range = start.blockRange(end);
60
+ if (range) {
61
+ const liftTarget = getListLiftTarget(start);
62
+ tr.lift(range, liftTarget);
63
+ }
64
+ return tr;
65
+ }
66
+ // The function will list paragraphs in selection out to level 1 below root list.
67
+ export function liftTextSelectionList(selection, tr) {
68
+ const {
69
+ from,
70
+ to
71
+ } = selection;
72
+ const {
73
+ paragraph
74
+ } = tr.doc.type.schema.nodes;
75
+ const listCol = [];
76
+ tr.doc.nodesBetween(from, to, (node, pos) => {
77
+ if (node.type === paragraph) {
78
+ listCol.push({
79
+ node,
80
+ pos
81
+ });
82
+ }
83
+ });
84
+ for (let i = listCol.length - 1; i >= 0; i--) {
85
+ const paragraph = listCol[i];
86
+ const start = tr.doc.resolve(tr.mapping.map(paragraph.pos));
87
+ if (start.depth > 0) {
88
+ let end;
89
+ if (paragraph.node.textContent && paragraph.node.textContent.length > 0) {
90
+ end = tr.doc.resolve(tr.mapping.map(paragraph.pos + paragraph.node.textContent.length));
91
+ } else {
92
+ end = tr.doc.resolve(tr.mapping.map(paragraph.pos + 1));
93
+ }
94
+ const range = start.blockRange(end);
95
+ if (range) {
96
+ tr.lift(range, getListLiftTarget(start));
97
+ }
98
+ }
99
+ }
100
+ return tr;
101
+ }
@@ -1 +1 @@
1
- export {};
1
+ export const MAX_NESTED_LIST_INDENTATION = 6;
@@ -0,0 +1,12 @@
1
+ export const RESTART_LISTS_ANALYTICS_KEY = 'restartListsAnalytics';
2
+ export const getRestartListsAttributes = tr => {
3
+ var _tr$getMeta;
4
+ return (_tr$getMeta = tr.getMeta(RESTART_LISTS_ANALYTICS_KEY)) !== null && _tr$getMeta !== void 0 ? _tr$getMeta : {};
5
+ };
6
+ export const storeRestartListsAttributes = (tr, attributes) => {
7
+ const meta = getRestartListsAttributes(tr);
8
+ tr.setMeta(RESTART_LISTS_ANALYTICS_KEY, {
9
+ ...meta,
10
+ ...attributes
11
+ });
12
+ };