@atlaskit/editor-plugin-tasks-and-decisions 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +26 -0
- package/CHANGELOG.md +10 -0
- package/dist/cjs/commands.js +288 -0
- package/dist/cjs/index.js +8 -1
- package/dist/cjs/nodeviews/decisionItem.js +117 -0
- package/dist/cjs/nodeviews/hooks/use-show-placeholder.js +40 -0
- package/dist/cjs/nodeviews/taskItem.js +211 -0
- package/dist/cjs/plugin.js +166 -0
- package/dist/cjs/pm-plugins/commands.js +96 -0
- package/dist/cjs/pm-plugins/helpers.js +299 -0
- package/dist/cjs/pm-plugins/input-rules.js +94 -0
- package/dist/cjs/pm-plugins/keymaps.js +376 -0
- package/dist/cjs/pm-plugins/main.js +263 -0
- package/dist/cjs/pm-plugins/plugin-key.js +8 -0
- package/dist/cjs/pm-plugins/types.js +11 -0
- package/dist/cjs/types.js +5 -0
- package/dist/cjs/ui/Decision/index.js +30 -0
- package/dist/cjs/ui/Task/index.js +81 -0
- package/dist/cjs/ui/Task/task-item-with-providers.js +138 -0
- package/dist/cjs/ui/ToolbarDecision/index.js +41 -0
- package/dist/cjs/ui/ToolbarTask/index.js +40 -0
- package/dist/cjs/utils.js +41 -0
- package/dist/es2019/commands.js +279 -0
- package/dist/es2019/index.js +1 -1
- package/dist/es2019/nodeviews/decisionItem.js +76 -0
- package/dist/es2019/nodeviews/hooks/use-show-placeholder.js +36 -0
- package/dist/es2019/nodeviews/taskItem.js +173 -0
- package/dist/es2019/plugin.js +154 -0
- package/dist/es2019/pm-plugins/commands.js +94 -0
- package/dist/es2019/pm-plugins/helpers.js +316 -0
- package/dist/es2019/pm-plugins/input-rules.js +91 -0
- package/dist/es2019/pm-plugins/keymaps.js +370 -0
- package/dist/es2019/pm-plugins/main.js +262 -0
- package/dist/es2019/pm-plugins/plugin-key.js +2 -0
- package/dist/es2019/pm-plugins/types.js +5 -0
- package/dist/es2019/types.js +1 -0
- package/dist/es2019/ui/Decision/index.js +26 -0
- package/dist/es2019/ui/Task/index.js +55 -0
- package/dist/es2019/ui/Task/task-item-with-providers.js +72 -0
- package/dist/es2019/ui/ToolbarDecision/index.js +37 -0
- package/dist/es2019/ui/ToolbarTask/index.js +36 -0
- package/dist/es2019/utils.js +32 -0
- package/dist/esm/commands.js +281 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/nodeviews/decisionItem.js +110 -0
- package/dist/esm/nodeviews/hooks/use-show-placeholder.js +34 -0
- package/dist/esm/nodeviews/taskItem.js +204 -0
- package/dist/esm/plugin.js +155 -0
- package/dist/esm/pm-plugins/commands.js +90 -0
- package/dist/esm/pm-plugins/helpers.js +285 -0
- package/dist/esm/pm-plugins/input-rules.js +87 -0
- package/dist/esm/pm-plugins/keymaps.js +368 -0
- package/dist/esm/pm-plugins/main.js +256 -0
- package/dist/esm/pm-plugins/plugin-key.js +2 -0
- package/dist/esm/pm-plugins/types.js +5 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/ui/Decision/index.js +23 -0
- package/dist/esm/ui/Task/index.js +71 -0
- package/dist/esm/ui/Task/task-item-with-providers.js +129 -0
- package/dist/esm/ui/ToolbarDecision/index.js +34 -0
- package/dist/esm/ui/ToolbarTask/index.js +33 -0
- package/dist/esm/utils.js +30 -0
- package/dist/types/commands.d.ts +16 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/nodeviews/decisionItem.d.ts +10 -0
- package/dist/types/nodeviews/hooks/use-show-placeholder.d.ts +11 -0
- package/dist/types/nodeviews/taskItem.d.ts +14 -0
- package/dist/types/plugin.d.ts +2 -0
- package/dist/types/pm-plugins/commands.d.ts +15 -0
- package/dist/types/pm-plugins/helpers.d.ts +76 -0
- package/dist/types/pm-plugins/input-rules.d.ts +6 -0
- package/dist/types/pm-plugins/keymaps.d.ts +11 -0
- package/dist/types/pm-plugins/main.d.ts +7 -0
- package/dist/types/pm-plugins/plugin-key.d.ts +2 -0
- package/dist/types/pm-plugins/types.d.ts +8 -0
- package/dist/types/types.d.ts +49 -0
- package/dist/types/ui/Decision/index.d.ts +15 -0
- package/dist/types/ui/Task/index.d.ts +28 -0
- package/dist/types/ui/Task/task-item-with-providers.d.ts +29 -0
- package/dist/types/ui/ToolbarDecision/index.d.ts +18 -0
- package/dist/types/ui/ToolbarTask/index.d.ts +18 -0
- package/dist/types/utils.d.ts +4 -0
- package/dist/types-ts4.5/commands.d.ts +16 -0
- package/dist/types-ts4.5/index.d.ts +2 -1
- package/dist/types-ts4.5/nodeviews/decisionItem.d.ts +10 -0
- package/dist/types-ts4.5/nodeviews/hooks/use-show-placeholder.d.ts +11 -0
- package/dist/types-ts4.5/nodeviews/taskItem.d.ts +14 -0
- package/dist/types-ts4.5/plugin.d.ts +2 -0
- package/dist/types-ts4.5/pm-plugins/commands.d.ts +15 -0
- package/dist/types-ts4.5/pm-plugins/helpers.d.ts +76 -0
- package/dist/types-ts4.5/pm-plugins/input-rules.d.ts +6 -0
- package/dist/types-ts4.5/pm-plugins/keymaps.d.ts +11 -0
- package/dist/types-ts4.5/pm-plugins/main.d.ts +7 -0
- package/dist/types-ts4.5/pm-plugins/plugin-key.d.ts +2 -0
- package/dist/types-ts4.5/pm-plugins/types.d.ts +8 -0
- package/dist/types-ts4.5/types.d.ts +49 -0
- package/dist/types-ts4.5/ui/Decision/index.d.ts +15 -0
- package/dist/types-ts4.5/ui/Task/index.d.ts +28 -0
- package/dist/types-ts4.5/ui/Task/task-item-with-providers.d.ts +29 -0
- package/dist/types-ts4.5/ui/ToolbarDecision/index.d.ts +18 -0
- package/dist/types-ts4.5/ui/ToolbarTask/index.d.ts +18 -0
- package/dist/types-ts4.5/utils.d.ts +4 -0
- package/package.json +16 -6
- package/report.api.md +100 -1
- package/tmp/api-report-tmp.d.ts +78 -0
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { findFarthestParentNode } from '@atlaskit/editor-common/utils';
|
|
2
|
+
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
3
|
+
import { liftTarget } from '@atlaskit/editor-prosemirror/transform';
|
|
4
|
+
import { findParentNodeClosestToPos, hasParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
|
|
5
|
+
import { stateKey } from './plugin-key';
|
|
6
|
+
import { ACTIONS } from './types';
|
|
7
|
+
export const isInsideTaskOrDecisionItem = state => {
|
|
8
|
+
const {
|
|
9
|
+
decisionItem,
|
|
10
|
+
taskItem
|
|
11
|
+
} = state.schema.nodes;
|
|
12
|
+
return hasParentNodeOfType([decisionItem, taskItem])(state.selection);
|
|
13
|
+
};
|
|
14
|
+
export const isActionOrDecisionList = node => {
|
|
15
|
+
const {
|
|
16
|
+
taskList,
|
|
17
|
+
decisionList
|
|
18
|
+
} = node.type.schema.nodes;
|
|
19
|
+
return [taskList, decisionList].indexOf(node.type) > -1;
|
|
20
|
+
};
|
|
21
|
+
export const isActionOrDecisionItem = node => {
|
|
22
|
+
const {
|
|
23
|
+
taskItem,
|
|
24
|
+
decisionItem
|
|
25
|
+
} = node.type.schema.nodes;
|
|
26
|
+
return [taskItem, decisionItem].indexOf(node.type) > -1;
|
|
27
|
+
};
|
|
28
|
+
export const isInsideTask = state => {
|
|
29
|
+
const {
|
|
30
|
+
taskItem
|
|
31
|
+
} = state.schema.nodes;
|
|
32
|
+
return hasParentNodeOfType([taskItem])(state.selection);
|
|
33
|
+
};
|
|
34
|
+
export const isInsideDecision = state => {
|
|
35
|
+
const {
|
|
36
|
+
decisionItem
|
|
37
|
+
} = state.schema.nodes;
|
|
38
|
+
return hasParentNodeOfType([decisionItem])(state.selection);
|
|
39
|
+
};
|
|
40
|
+
export const isTable = node => {
|
|
41
|
+
if (!node) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
const {
|
|
45
|
+
table,
|
|
46
|
+
tableHeader,
|
|
47
|
+
tableCell,
|
|
48
|
+
tableRow
|
|
49
|
+
} = node.type.schema.nodes;
|
|
50
|
+
return [table, tableHeader, tableCell, tableRow].includes(node.type);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Creates a NodeRange around the given taskItem and the following
|
|
55
|
+
* ("nested") taskList, if one exists.
|
|
56
|
+
*/
|
|
57
|
+
export const getBlockRange = ($from, $to) => {
|
|
58
|
+
const {
|
|
59
|
+
taskList
|
|
60
|
+
} = $from.doc.type.schema.nodes;
|
|
61
|
+
let end = $to.end();
|
|
62
|
+
const $after = $to.doc.resolve(end + 1);
|
|
63
|
+
const after = $after.nodeAfter;
|
|
64
|
+
|
|
65
|
+
// ensure the node after is actually just a sibling
|
|
66
|
+
// $to will be inside the text, so subtract one to get the taskItem it contains in
|
|
67
|
+
if (after && after.type === taskList && $after.depth === $to.depth - 1) {
|
|
68
|
+
// it was! include it in our blockRange
|
|
69
|
+
end += after.nodeSize;
|
|
70
|
+
}
|
|
71
|
+
return $from.blockRange($to.doc.resolve(end));
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Finds the distance between the current $from and the root of the taskList.
|
|
76
|
+
*/
|
|
77
|
+
export const getCurrentIndentLevel = selection => {
|
|
78
|
+
const {
|
|
79
|
+
$from
|
|
80
|
+
} = selection;
|
|
81
|
+
const {
|
|
82
|
+
taskList
|
|
83
|
+
} = $from.doc.type.schema.nodes;
|
|
84
|
+
const furthestParent = findFarthestParentNode(node => node.type === taskList)($from);
|
|
85
|
+
if (!furthestParent) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
return $from.depth - furthestParent.depth;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Finds the index of the current task item in relation to the closest taskList
|
|
93
|
+
*/
|
|
94
|
+
export const getTaskItemIndex = state => {
|
|
95
|
+
const $pos = state.selection.$from;
|
|
96
|
+
const isTaskList = node => (node === null || node === void 0 ? void 0 : node.type.name) === 'taskList';
|
|
97
|
+
const itemAtPos = findParentNodeClosestToPos($pos, isTaskList);
|
|
98
|
+
return $pos.index(itemAtPos ? itemAtPos.depth : undefined);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Walk outwards from a position until we encounter the (inside) start of
|
|
103
|
+
* the next node, or reach the end of the document.
|
|
104
|
+
*
|
|
105
|
+
* @param $startPos Position to start walking from.
|
|
106
|
+
*/
|
|
107
|
+
export const walkOut = $startPos => {
|
|
108
|
+
let $pos = $startPos;
|
|
109
|
+
|
|
110
|
+
// invariant 1: don't walk past the end of the document
|
|
111
|
+
// invariant 2: we haven't walked to the start of *any* node
|
|
112
|
+
// parentOffset includes textOffset.
|
|
113
|
+
while ($pos.pos < $pos.doc.nodeSize - 2 && $pos.parentOffset > 0) {
|
|
114
|
+
$pos = $pos.doc.resolve($pos.pos + 1);
|
|
115
|
+
}
|
|
116
|
+
return $pos;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Finds the height of a tree-like structure, given any position inside it.
|
|
121
|
+
*
|
|
122
|
+
* Traverses from the top of the tree to all leaf nodes, and returns the length
|
|
123
|
+
* of the longest path.
|
|
124
|
+
*
|
|
125
|
+
* This means you can use it with things like taskList, which
|
|
126
|
+
* do not nest themselves inside taskItems but rather as adjacent children.
|
|
127
|
+
*
|
|
128
|
+
* @param $pos Any position inside the tree.
|
|
129
|
+
* @param types The node types to consider traversable
|
|
130
|
+
*/
|
|
131
|
+
export const subtreeHeight = ($from, $to, types) => {
|
|
132
|
+
const root = findFarthestParentNode(node => types.indexOf(node.type) > -1)($from);
|
|
133
|
+
if (!root) {
|
|
134
|
+
return -1;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// get the height between the root and the current position
|
|
138
|
+
const distToParent = $from.depth - root.depth;
|
|
139
|
+
|
|
140
|
+
// include any following taskList since nested lists appear
|
|
141
|
+
// as siblings
|
|
142
|
+
//
|
|
143
|
+
// this is unlike regular bullet lists where the orderedList
|
|
144
|
+
// appears as descendent of listItem
|
|
145
|
+
const blockRange = getBlockRange($from, $to);
|
|
146
|
+
if (!blockRange) {
|
|
147
|
+
return -1;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// and get the max height from the current position to the
|
|
151
|
+
// deepest leaf node
|
|
152
|
+
let maxChildDepth = $from.depth;
|
|
153
|
+
$from.doc.nodesBetween(blockRange.start, blockRange.end, (descendent, relPos, parent) => {
|
|
154
|
+
maxChildDepth = Math.max($from.doc.resolve(relPos).depth, maxChildDepth);
|
|
155
|
+
|
|
156
|
+
// keep descending down the tree if we can
|
|
157
|
+
if (types.indexOf(descendent.type) > -1) {
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
return distToParent + (maxChildDepth - $from.depth);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Returns `true` if the taskItem or decisionItem has no text.
|
|
166
|
+
*/
|
|
167
|
+
export const isEmptyTaskDecision = state => {
|
|
168
|
+
const {
|
|
169
|
+
selection,
|
|
170
|
+
schema
|
|
171
|
+
} = state;
|
|
172
|
+
const {
|
|
173
|
+
$from
|
|
174
|
+
} = selection;
|
|
175
|
+
const node = $from.node($from.depth);
|
|
176
|
+
return node && (node.type === schema.nodes.taskItem || node.type === schema.nodes.decisionItem) && node.content.size === 0;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Lifts a taskItem and any directly following taskList
|
|
181
|
+
* (taskItem and its "nested children") out one level.
|
|
182
|
+
*
|
|
183
|
+
* @param tr Transaction to base steps on
|
|
184
|
+
* @param $from Start of range you want to lift
|
|
185
|
+
* @param $to End of range you want to lift (can be same as `$from`)
|
|
186
|
+
*/
|
|
187
|
+
export const liftBlock = (tr, $from, $to) => {
|
|
188
|
+
const blockRange = getBlockRange($from, $to);
|
|
189
|
+
if (!blockRange) {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ensure we can actually lift
|
|
194
|
+
const target = liftTarget(blockRange);
|
|
195
|
+
if (typeof target !== 'number') {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
return tr.lift(blockRange, target).scrollIntoView();
|
|
199
|
+
};
|
|
200
|
+
export function getTaskItemDataAtPos(view) {
|
|
201
|
+
const {
|
|
202
|
+
state
|
|
203
|
+
} = view;
|
|
204
|
+
const {
|
|
205
|
+
selection,
|
|
206
|
+
schema
|
|
207
|
+
} = state;
|
|
208
|
+
const {
|
|
209
|
+
$from
|
|
210
|
+
} = selection;
|
|
211
|
+
const isInTaskItem = $from.node().type === schema.nodes.taskItem;
|
|
212
|
+
|
|
213
|
+
// current selection has to be inside taskitem
|
|
214
|
+
if (isInTaskItem) {
|
|
215
|
+
const taskItemPos = $from.before();
|
|
216
|
+
return {
|
|
217
|
+
pos: taskItemPos,
|
|
218
|
+
localId: $from.node().attrs.localId
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
export function getAllTaskItemsDataInRootTaskList(view) {
|
|
223
|
+
const {
|
|
224
|
+
state
|
|
225
|
+
} = view;
|
|
226
|
+
const {
|
|
227
|
+
schema
|
|
228
|
+
} = state;
|
|
229
|
+
const $fromPos = state.selection.$from;
|
|
230
|
+
const isInTaskItem = $fromPos.node().type === schema.nodes.taskItem;
|
|
231
|
+
// if not inside task item then return undefined;
|
|
232
|
+
if (!isInTaskItem) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const {
|
|
236
|
+
taskList,
|
|
237
|
+
taskItem
|
|
238
|
+
} = schema.nodes;
|
|
239
|
+
const rootTaskListData = findFarthestParentNode(node => node.type === taskList)($fromPos);
|
|
240
|
+
if (rootTaskListData) {
|
|
241
|
+
const rootTaskList = rootTaskListData.node;
|
|
242
|
+
const rootTaskListStartPos = rootTaskListData.start;
|
|
243
|
+
const allTaskItems = [];
|
|
244
|
+
rootTaskList.descendants((node, pos, parent, index) => {
|
|
245
|
+
if (node.type === taskItem) {
|
|
246
|
+
allTaskItems.push({
|
|
247
|
+
node,
|
|
248
|
+
pos: pos + rootTaskListStartPos,
|
|
249
|
+
index
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
return allTaskItems;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
export function getCurrentTaskItemIndex(view, allTaskItems) {
|
|
257
|
+
const {
|
|
258
|
+
state
|
|
259
|
+
} = view;
|
|
260
|
+
const $fromPos = state.selection.$from;
|
|
261
|
+
const allTaskItemNodes = allTaskItems.map(nodeData => nodeData.node);
|
|
262
|
+
const currentTaskItem = $fromPos.node($fromPos.depth);
|
|
263
|
+
const currentTaskItemIndex = allTaskItemNodes.indexOf(currentTaskItem);
|
|
264
|
+
return currentTaskItemIndex;
|
|
265
|
+
}
|
|
266
|
+
export function getTaskItemDataToFocus(view, direction) {
|
|
267
|
+
const allTaskItems = getAllTaskItemsDataInRootTaskList(view);
|
|
268
|
+
// if not inside task item then allTaskItems will be undefined;
|
|
269
|
+
if (!allTaskItems) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
const currentTaskItemIndex = getCurrentTaskItemIndex(view, allTaskItems);
|
|
273
|
+
if (direction === 'next' ? currentTaskItemIndex === allTaskItems.length - 1 : currentTaskItemIndex === 0) {
|
|
274
|
+
// checkbox of first or last task item is already focused based on direction.
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const indexOfTaskItemToFocus = direction === 'next' ? currentTaskItemIndex + 1 : currentTaskItemIndex - 1;
|
|
278
|
+
const taskItemToFocus = allTaskItems[indexOfTaskItemToFocus];
|
|
279
|
+
return {
|
|
280
|
+
pos: taskItemToFocus.pos,
|
|
281
|
+
localId: taskItemToFocus.node.attrs.localId
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
export function focusCheckboxAndUpdateSelection(view, taskItemData) {
|
|
285
|
+
const {
|
|
286
|
+
pos,
|
|
287
|
+
localId
|
|
288
|
+
} = taskItemData;
|
|
289
|
+
const {
|
|
290
|
+
state,
|
|
291
|
+
dispatch
|
|
292
|
+
} = view;
|
|
293
|
+
const {
|
|
294
|
+
doc,
|
|
295
|
+
tr
|
|
296
|
+
} = state;
|
|
297
|
+
tr.setSelection(new TextSelection(doc.resolve(pos + 1)));
|
|
298
|
+
tr.setMeta(stateKey, {
|
|
299
|
+
action: ACTIONS.FOCUS_BY_LOCALID,
|
|
300
|
+
data: localId
|
|
301
|
+
});
|
|
302
|
+
dispatch(tr);
|
|
303
|
+
}
|
|
304
|
+
export function removeCheckboxFocus(view) {
|
|
305
|
+
const {
|
|
306
|
+
state,
|
|
307
|
+
dispatch
|
|
308
|
+
} = view;
|
|
309
|
+
const {
|
|
310
|
+
tr
|
|
311
|
+
} = state;
|
|
312
|
+
view.focus();
|
|
313
|
+
dispatch(tr.setMeta(stateKey, {
|
|
314
|
+
action: ACTIONS.FOCUS_BY_LOCALID
|
|
315
|
+
}));
|
|
316
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
2
|
+
import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
3
|
+
import { canInsert } from '@atlaskit/editor-prosemirror/utils';
|
|
4
|
+
import { createPlugin, createRule, leafNodeReplacementCharacter } from '@atlaskit/prosemirror-input-rules';
|
|
5
|
+
import { changeInDepth, getListTypes, insertTaskDecisionAction } from '../commands';
|
|
6
|
+
const createListRule = editorAnalyticsAPI => (regex, listType, itemAttrs) => {
|
|
7
|
+
return createRule(regex, (state, _match, start, end) => {
|
|
8
|
+
const {
|
|
9
|
+
paragraph
|
|
10
|
+
} = state.schema.nodes;
|
|
11
|
+
const {
|
|
12
|
+
list
|
|
13
|
+
} = getListTypes(listType, state.schema);
|
|
14
|
+
const $end = state.doc.resolve(end);
|
|
15
|
+
const $endOfParent = state.doc.resolve($end.after());
|
|
16
|
+
// Only allow creating list in nodes that support them.
|
|
17
|
+
// Parent must be a paragraph as we don't want this applying to headings
|
|
18
|
+
if ($end.parent.type !== paragraph || !canInsert($endOfParent, list.createAndFill())) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const insertTr = insertTaskDecisionAction(editorAnalyticsAPI)(state, listType, INPUT_METHOD.FORMATTING, addItem(start, end), undefined, undefined, itemAttrs);
|
|
22
|
+
return insertTr;
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
const addItem = (start, end) => ({
|
|
26
|
+
tr,
|
|
27
|
+
state,
|
|
28
|
+
list,
|
|
29
|
+
item,
|
|
30
|
+
listLocalId,
|
|
31
|
+
itemLocalId,
|
|
32
|
+
itemAttrs
|
|
33
|
+
}) => {
|
|
34
|
+
const {
|
|
35
|
+
selection: {
|
|
36
|
+
$from
|
|
37
|
+
},
|
|
38
|
+
schema
|
|
39
|
+
} = state;
|
|
40
|
+
const {
|
|
41
|
+
hardBreak
|
|
42
|
+
} = schema.nodes;
|
|
43
|
+
const content = $from.node($from.depth).content;
|
|
44
|
+
let shouldBreakNode = false;
|
|
45
|
+
content.forEach((node, offset) => {
|
|
46
|
+
if (node.type === hardBreak && offset < start) {
|
|
47
|
+
shouldBreakNode = true;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
if (!shouldBreakNode) {
|
|
51
|
+
tr.replaceRangeWith($from.before(), $from.after(), list.create({
|
|
52
|
+
localId: listLocalId
|
|
53
|
+
}, [item.create({
|
|
54
|
+
localId: itemLocalId,
|
|
55
|
+
...itemAttrs
|
|
56
|
+
}, content)])).delete(start + 1, end + 1).setSelection(new TextSelection(tr.doc.resolve(start + 1)));
|
|
57
|
+
} else {
|
|
58
|
+
const depthAdjustment = changeInDepth($from, tr.selection.$from);
|
|
59
|
+
tr.split($from.pos).setSelection(new NodeSelection(tr.doc.resolve($from.pos + 1))).replaceSelectionWith(list.create({
|
|
60
|
+
localId: listLocalId
|
|
61
|
+
}, [item.create({
|
|
62
|
+
localId: itemLocalId,
|
|
63
|
+
...itemAttrs
|
|
64
|
+
},
|
|
65
|
+
// TODO: [ts30] handle void and null properly
|
|
66
|
+
tr.doc.nodeAt($from.pos + 1).content)])).setSelection(new TextSelection(tr.doc.resolve($from.pos + depthAdjustment))).delete(start, end + 1);
|
|
67
|
+
}
|
|
68
|
+
return tr;
|
|
69
|
+
};
|
|
70
|
+
export const inputRulePlugin = editorAnalyticsAPI => (schema, featureFlags) => {
|
|
71
|
+
const rules = [];
|
|
72
|
+
const {
|
|
73
|
+
decisionList,
|
|
74
|
+
decisionItem,
|
|
75
|
+
taskList,
|
|
76
|
+
taskItem
|
|
77
|
+
} = schema.nodes;
|
|
78
|
+
if (decisionList && decisionItem) {
|
|
79
|
+
rules.push(createListRule(editorAnalyticsAPI)(new RegExp(`(^|${leafNodeReplacementCharacter})\\<\\>\\s$`), 'decisionList'));
|
|
80
|
+
}
|
|
81
|
+
if (taskList && taskItem) {
|
|
82
|
+
rules.push(createListRule(editorAnalyticsAPI)(new RegExp(`(^|${leafNodeReplacementCharacter})\\[\\]\\s$`), 'taskList'));
|
|
83
|
+
rules.push(createListRule(editorAnalyticsAPI)(new RegExp(`(^|${leafNodeReplacementCharacter})\\[x\\]\\s$`), 'taskList', {
|
|
84
|
+
state: 'DONE'
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
return createPlugin('tasks-and-decisions', rules, {
|
|
88
|
+
isBlockNodeRule: true
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
export default inputRulePlugin;
|