@atlaskit/editor-common 74.30.0 → 74.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/cjs/lists/analytics.js +40 -0
- package/dist/cjs/lists/indentation.js +24 -0
- package/dist/cjs/lists/index.js +89 -0
- package/dist/cjs/lists/node.js +97 -0
- package/dist/cjs/lists/replace-content.js +24 -0
- package/dist/cjs/lists/selection.js +59 -0
- package/dist/cjs/monitoring/error.js +1 -1
- package/dist/cjs/node-width/index.js +10 -2
- package/dist/cjs/ui/DropList/index.js +1 -1
- package/dist/cjs/utils/commands.js +110 -2
- package/dist/cjs/utils/document.js +26 -1
- package/dist/cjs/utils/index.js +51 -2
- package/dist/cjs/utils/prosemirror/autojoin.js +68 -0
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/lists/analytics.js +36 -0
- package/dist/es2019/lists/indentation.js +18 -0
- package/dist/es2019/lists/index.js +6 -0
- package/dist/es2019/lists/node.js +97 -0
- package/dist/es2019/lists/replace-content.js +18 -0
- package/dist/es2019/lists/selection.js +53 -0
- package/dist/es2019/monitoring/error.js +1 -1
- package/dist/es2019/node-width/index.js +7 -0
- package/dist/es2019/ui/DropList/index.js +1 -1
- package/dist/es2019/utils/commands.js +106 -2
- package/dist/es2019/utils/document.js +25 -1
- package/dist/es2019/utils/index.js +3 -2
- package/dist/es2019/utils/prosemirror/autojoin.js +57 -0
- package/dist/es2019/version.json +1 -1
- package/dist/esm/lists/analytics.js +32 -0
- package/dist/esm/lists/indentation.js +17 -0
- package/dist/esm/lists/index.js +6 -0
- package/dist/esm/lists/node.js +87 -0
- package/dist/esm/lists/replace-content.js +17 -0
- package/dist/esm/lists/selection.js +50 -0
- package/dist/esm/monitoring/error.js +1 -1
- package/dist/esm/node-width/index.js +7 -0
- package/dist/esm/ui/DropList/index.js +1 -1
- package/dist/esm/utils/commands.js +104 -2
- package/dist/esm/utils/document.js +25 -1
- package/dist/esm/utils/index.js +3 -2
- package/dist/esm/utils/prosemirror/autojoin.js +63 -0
- package/dist/esm/version.json +1 -1
- package/dist/types/lists/analytics.d.ts +4 -0
- package/dist/types/lists/indentation.d.ts +5 -0
- package/dist/types/lists/index.d.ts +6 -0
- package/dist/types/lists/node.d.ts +18 -0
- package/dist/types/lists/replace-content.d.ts +8 -0
- package/dist/types/lists/selection.d.ts +13 -0
- package/dist/types/node-width/index.d.ts +1 -0
- package/dist/types/utils/commands.d.ts +36 -2
- package/dist/types/utils/document.d.ts +4 -0
- package/dist/types/utils/index.d.ts +4 -2
- package/dist/types/utils/prosemirror/autojoin.d.ts +13 -0
- package/dist/types-ts4.5/lists/analytics.d.ts +4 -0
- package/dist/types-ts4.5/lists/indentation.d.ts +5 -0
- package/dist/types-ts4.5/lists/index.d.ts +6 -0
- package/dist/types-ts4.5/lists/node.d.ts +18 -0
- package/dist/types-ts4.5/lists/replace-content.d.ts +8 -0
- package/dist/types-ts4.5/lists/selection.d.ts +13 -0
- package/dist/types-ts4.5/node-width/index.d.ts +1 -0
- package/dist/types-ts4.5/utils/commands.d.ts +42 -2
- package/dist/types-ts4.5/utils/document.d.ts +4 -0
- package/dist/types-ts4.5/utils/index.d.ts +4 -2
- package/dist/types-ts4.5/utils/prosemirror/autojoin.d.ts +13 -0
- package/lists/package.json +15 -0
- package/package.json +3 -2
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.autoJoinTr = autoJoinTr;
|
|
7
|
+
var _transform = require("@atlaskit/editor-prosemirror/transform");
|
|
8
|
+
/**
|
|
9
|
+
* Checks whether two adjacent nodes can be joined. If so, the document
|
|
10
|
+
* will be updated to join those nodes. If not, the original transaction
|
|
11
|
+
* remains untouched.
|
|
12
|
+
*
|
|
13
|
+
* Nodes are considered joinable if the `isJoinable` predicate returns true or,
|
|
14
|
+
* if an array of strings was passed, if their node type name is in that array.
|
|
15
|
+
*
|
|
16
|
+
* Adapted from https://github.com/ProseMirror/prosemirror-commands/blob/master/src/commands.js#L597-L610
|
|
17
|
+
*/
|
|
18
|
+
function autoJoinTr(tr, isJoinable) {
|
|
19
|
+
if (Array.isArray(isJoinable)) {
|
|
20
|
+
var types = isJoinable;
|
|
21
|
+
isJoinable = function isJoinable(node) {
|
|
22
|
+
return types.indexOf(node.type.name) > -1;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
var ranges = [];
|
|
26
|
+
for (var i = 0; i < tr.mapping.maps.length; i++) {
|
|
27
|
+
var map = tr.mapping.maps[i];
|
|
28
|
+
for (var j = 0; j < ranges.length; j++) {
|
|
29
|
+
ranges[j] = map.map(ranges[j]);
|
|
30
|
+
}
|
|
31
|
+
map.forEach(function (_s, _e, from, to) {
|
|
32
|
+
return ranges.push(from, to);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Figure out which joinable points exist inside those ranges,
|
|
37
|
+
// by checking all node boundaries in their parent nodes.
|
|
38
|
+
var joinable = [];
|
|
39
|
+
for (var _i = 0; _i < ranges.length; _i += 2) {
|
|
40
|
+
var from = ranges[_i];
|
|
41
|
+
var to = ranges[_i + 1];
|
|
42
|
+
var $from = tr.doc.resolve(from);
|
|
43
|
+
var depth = $from.sharedDepth(to);
|
|
44
|
+
var parent = $from.node(depth);
|
|
45
|
+
for (var index = $from.indexAfter(depth), pos = $from.after(depth + 1); pos <= to; ++index) {
|
|
46
|
+
var _after = parent.maybeChild(index);
|
|
47
|
+
if (!_after) {
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
if (index && joinable.indexOf(pos) === -1) {
|
|
51
|
+
var _before = parent.child(index - 1);
|
|
52
|
+
if (_before.type === _after.type && isJoinable(_before, _after)) {
|
|
53
|
+
joinable.push(pos);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
pos += _after.nodeSize;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Join the joinable points
|
|
60
|
+
joinable.sort(function (a, b) {
|
|
61
|
+
return a - b;
|
|
62
|
+
});
|
|
63
|
+
for (var _i2 = joinable.length - 1; _i2 >= 0; _i2--) {
|
|
64
|
+
if ((0, _transform.canJoin)(tr.doc, joinable[_i2])) {
|
|
65
|
+
tr.join(joinable[_i2]);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
package/dist/cjs/version.json
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { isListItemNode, isListNode } from '../utils';
|
|
2
|
+
import { getListItemAttributes } from './selection';
|
|
3
|
+
export const getCommonListAnalyticsAttributes = state => {
|
|
4
|
+
const {
|
|
5
|
+
selection: {
|
|
6
|
+
$from,
|
|
7
|
+
$to
|
|
8
|
+
}
|
|
9
|
+
} = state;
|
|
10
|
+
const fromAttrs = getListItemAttributes($from);
|
|
11
|
+
const toAttrs = getListItemAttributes($to);
|
|
12
|
+
return {
|
|
13
|
+
itemIndexAtSelectionStart: fromAttrs.itemIndex,
|
|
14
|
+
itemIndexAtSelectionEnd: toAttrs.itemIndex,
|
|
15
|
+
indentLevelAtSelectionStart: fromAttrs.indentLevel,
|
|
16
|
+
indentLevelAtSelectionEnd: toAttrs.indentLevel,
|
|
17
|
+
itemsInSelection: countListItemsInSelection(state)
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export const countListItemsInSelection = state => {
|
|
21
|
+
const {
|
|
22
|
+
from,
|
|
23
|
+
to
|
|
24
|
+
} = state.selection;
|
|
25
|
+
if (from === to) {
|
|
26
|
+
return 1;
|
|
27
|
+
}
|
|
28
|
+
let count = 0;
|
|
29
|
+
const listSlice = state.doc.cut(from, to);
|
|
30
|
+
listSlice.content.nodesBetween(0, listSlice.content.size, (node, pos, parent, index) => {
|
|
31
|
+
if (parent && isListItemNode(parent) && !isListNode(node) && index === 0) {
|
|
32
|
+
count++;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return count;
|
|
36
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { numberNestedLists } from './selection';
|
|
2
|
+
export const hasValidListIndentationLevel = ({
|
|
3
|
+
tr,
|
|
4
|
+
maxIndentation
|
|
5
|
+
}) => {
|
|
6
|
+
const initialIndentationLevel = numberNestedLists(tr.selection.$from);
|
|
7
|
+
let currentIndentationLevel;
|
|
8
|
+
let currentPos = tr.selection.$to.pos;
|
|
9
|
+
do {
|
|
10
|
+
const resolvedPos = tr.doc.resolve(currentPos);
|
|
11
|
+
currentIndentationLevel = numberNestedLists(resolvedPos);
|
|
12
|
+
if (currentIndentationLevel > maxIndentation) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
currentPos++;
|
|
16
|
+
} while (currentIndentationLevel >= initialIndentationLevel);
|
|
17
|
+
return true;
|
|
18
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { getListItemAttributes, normalizeListItemsSelection } from './selection';
|
|
2
|
+
export { moveTargetIntoList } from './replace-content';
|
|
3
|
+
export { JoinDirection, isListNodeValidContent, joinSiblingLists } from './node';
|
|
4
|
+
export { getCommonListAnalyticsAttributes, countListItemsInSelection } from './analytics';
|
|
5
|
+
export { hasValidListIndentationLevel } from './indentation';
|
|
6
|
+
export { isListNode, isListItemNode, isBulletList, isParagraphNode } from '../utils';
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
+
import { isListItemNode, isListNode } from '../utils';
|
|
3
|
+
export function isListNodeValidContent(node) {
|
|
4
|
+
const {
|
|
5
|
+
bulletList
|
|
6
|
+
} = node.type.schema.nodes;
|
|
7
|
+
if (!bulletList) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
const listFragment = Fragment.from(bulletList.createAndFill());
|
|
11
|
+
return !isListItemNode(node) && node.type.validContent(listFragment);
|
|
12
|
+
}
|
|
13
|
+
export let JoinDirection = /*#__PURE__*/function (JoinDirection) {
|
|
14
|
+
JoinDirection[JoinDirection["LEFT"] = 1] = "LEFT";
|
|
15
|
+
JoinDirection[JoinDirection["RIGHT"] = -1] = "RIGHT";
|
|
16
|
+
return JoinDirection;
|
|
17
|
+
}({});
|
|
18
|
+
export const joinSiblingLists = ({
|
|
19
|
+
tr,
|
|
20
|
+
direction,
|
|
21
|
+
forceListType
|
|
22
|
+
}) => {
|
|
23
|
+
const result = {
|
|
24
|
+
orderedList: 0,
|
|
25
|
+
bulletList: 0
|
|
26
|
+
};
|
|
27
|
+
const {
|
|
28
|
+
doc,
|
|
29
|
+
selection: {
|
|
30
|
+
$from,
|
|
31
|
+
$to
|
|
32
|
+
},
|
|
33
|
+
selection
|
|
34
|
+
} = tr;
|
|
35
|
+
const range = $from.blockRange($to, isListNodeValidContent);
|
|
36
|
+
if (!range) {
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
const rootListNode = doc.nodeAt(range.start);
|
|
40
|
+
const from = isListNode(rootListNode) ? range.start : 0;
|
|
41
|
+
const to = isListNode(rootListNode) ? range.end : tr.doc.content.size;
|
|
42
|
+
const joins = [];
|
|
43
|
+
doc.nodesBetween(from, to, (node, pos, parent) => {
|
|
44
|
+
const resolvedPos = doc.resolve(pos);
|
|
45
|
+
const {
|
|
46
|
+
nodeBefore,
|
|
47
|
+
nodeAfter
|
|
48
|
+
} = resolvedPos;
|
|
49
|
+
if (!nodeBefore || !nodeAfter || !isListNode(nodeBefore) || !isListNode(nodeAfter)) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const isNestedList = isListItemNode(parent);
|
|
53
|
+
if (!isNestedList && nodeBefore.type !== nodeAfter.type && !forceListType) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const index = resolvedPos.index();
|
|
57
|
+
const positionPreviousNode = resolvedPos.posAtIndex(index - 1);
|
|
58
|
+
const positionCurrentNode = resolvedPos.posAtIndex(index);
|
|
59
|
+
|
|
60
|
+
// If the previous node is part of the selection, OR
|
|
61
|
+
// If the previous node is not part of the selection and the previous node has the same list type that we’re converting to
|
|
62
|
+
const joinBefore = positionPreviousNode >= from || nodeBefore.type === forceListType;
|
|
63
|
+
if (forceListType) {
|
|
64
|
+
if (joinBefore) {
|
|
65
|
+
tr.setNodeMarkup(positionPreviousNode, forceListType);
|
|
66
|
+
}
|
|
67
|
+
tr.setNodeMarkup(positionCurrentNode, forceListType);
|
|
68
|
+
}
|
|
69
|
+
if (isNestedList && nodeBefore.type !== nodeAfter.type) {
|
|
70
|
+
const nodeType = direction === JoinDirection.RIGHT ? nodeAfter.type : nodeBefore.type;
|
|
71
|
+
tr.setNodeMarkup(positionPreviousNode, nodeType);
|
|
72
|
+
}
|
|
73
|
+
if (joinBefore) {
|
|
74
|
+
joins.push(pos);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
if (selection.empty && rootListNode && isListNode(rootListNode)) {
|
|
78
|
+
const resolvedPos = doc.resolve(range.start + rootListNode.nodeSize);
|
|
79
|
+
const {
|
|
80
|
+
nodeBefore,
|
|
81
|
+
nodeAfter
|
|
82
|
+
} = resolvedPos;
|
|
83
|
+
if (nodeBefore && nodeAfter && isListNode(nodeBefore) && isListNode(nodeAfter) && nodeAfter.type === nodeBefore.type) {
|
|
84
|
+
joins.push(resolvedPos.pos);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
for (let i = joins.length - 1; i >= 0; i--) {
|
|
88
|
+
const listNode = tr.doc.nodeAt(joins[i]);
|
|
89
|
+
const listName = listNode === null || listNode === void 0 ? void 0 : listNode.type.name;
|
|
90
|
+
if (listName && (listName === 'orderedList' || listName === 'bulletList')) {
|
|
91
|
+
const amount = result[listName] || 0;
|
|
92
|
+
result[listName] = amount + 1;
|
|
93
|
+
}
|
|
94
|
+
tr.join(joins[i]);
|
|
95
|
+
}
|
|
96
|
+
return result;
|
|
97
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
|
|
2
|
+
export const moveTargetIntoList = ({
|
|
3
|
+
insertPosition,
|
|
4
|
+
$target
|
|
5
|
+
}) => {
|
|
6
|
+
var _$target$nodeAfter;
|
|
7
|
+
// take the text content of the paragraph and insert after the paragraph up until before the the cut
|
|
8
|
+
const from = insertPosition;
|
|
9
|
+
const to = $target.pos + (((_$target$nodeAfter = $target.nodeAfter) === null || _$target$nodeAfter === void 0 ? void 0 : _$target$nodeAfter.nodeSize) || 0); //$cut.pos + $cut.nodeAfter.nodeSize;
|
|
10
|
+
const gapFrom = $target.posAtIndex(0, $target.depth + 1); // start pos of the child
|
|
11
|
+
const gapTo = $target.doc.resolve(gapFrom).end(); // end pos of the paragraph
|
|
12
|
+
|
|
13
|
+
if (gapTo - gapFrom === 0) {
|
|
14
|
+
return new ReplaceStep(from, to, $target.doc.slice(insertPosition, $target.pos));
|
|
15
|
+
}
|
|
16
|
+
const step = new ReplaceAroundStep(from, to, gapFrom, gapTo, $target.doc.slice(insertPosition, $target.pos), 0, true);
|
|
17
|
+
return step;
|
|
18
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { NodeSelection, Selection, TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
import { findParentNodeClosestToPos } from '@atlaskit/editor-prosemirror/utils';
|
|
3
|
+
import { isListItemNode, isListNode } from '../utils';
|
|
4
|
+
export const numberNestedLists = resolvedPos => {
|
|
5
|
+
let count = 0;
|
|
6
|
+
for (let i = resolvedPos.depth - 1; i > 0; i--) {
|
|
7
|
+
const node = resolvedPos.node(i);
|
|
8
|
+
if (isListNode(node)) {
|
|
9
|
+
count += 1;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return count;
|
|
13
|
+
};
|
|
14
|
+
export const getListItemAttributes = $pos => {
|
|
15
|
+
const indentLevel = numberNestedLists($pos) - 1;
|
|
16
|
+
const itemAtPos = findParentNodeClosestToPos($pos, isListItemNode);
|
|
17
|
+
|
|
18
|
+
// Get the index of the current item relative to parent (parent is at item depth - 1)
|
|
19
|
+
const itemIndex = $pos.index(itemAtPos ? itemAtPos.depth - 1 : undefined);
|
|
20
|
+
return {
|
|
21
|
+
indentLevel,
|
|
22
|
+
itemIndex
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export const normalizeListItemsSelection = ({
|
|
26
|
+
selection,
|
|
27
|
+
doc
|
|
28
|
+
}) => {
|
|
29
|
+
if (selection.empty) {
|
|
30
|
+
return selection;
|
|
31
|
+
}
|
|
32
|
+
const {
|
|
33
|
+
$from,
|
|
34
|
+
$to
|
|
35
|
+
} = selection;
|
|
36
|
+
if (selection instanceof NodeSelection) {
|
|
37
|
+
const head = resolvePositionToStartOfListItem($from);
|
|
38
|
+
return new TextSelection(head, head);
|
|
39
|
+
}
|
|
40
|
+
const head = resolvePositionToStartOfListItem($from);
|
|
41
|
+
const anchor = resolvePositionToEndOfListItem($to);
|
|
42
|
+
return new TextSelection(anchor, head);
|
|
43
|
+
};
|
|
44
|
+
const resolvePositionToStartOfListItem = $pos => {
|
|
45
|
+
const fromRange = $pos.blockRange($pos, isListItemNode);
|
|
46
|
+
const fromPosition = fromRange && $pos.textOffset === 0 && fromRange.end - 1 === $pos.pos ? Selection.near($pos.doc.resolve(fromRange.end + 1), 1).$from : $pos;
|
|
47
|
+
return fromPosition;
|
|
48
|
+
};
|
|
49
|
+
const resolvePositionToEndOfListItem = $pos => {
|
|
50
|
+
const toRange = $pos.blockRange($pos, isListItemNode);
|
|
51
|
+
const toPosition = toRange && $pos.textOffset === 0 && toRange.start + 1 === $pos.pos ? Selection.near($pos.doc.resolve(toRange.start - 1), -1).$to : $pos;
|
|
52
|
+
return toPosition;
|
|
53
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
|
|
2
2
|
const packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
|
|
3
|
-
const packageVersion = "74.
|
|
3
|
+
const packageVersion = "74.31.0";
|
|
4
4
|
const sanitiseSentryEvents = (data, _hint) => {
|
|
5
5
|
// Remove URL as it has UGC
|
|
6
6
|
// TODO: Sanitise the URL instead of just removing it
|
|
@@ -102,4 +102,11 @@ export const getTableContainerWidth = node => {
|
|
|
102
102
|
return node.attrs.width;
|
|
103
103
|
}
|
|
104
104
|
return layoutToWidth[node.attrs.layout];
|
|
105
|
+
};
|
|
106
|
+
export const getTableWidthWithNumberColumn = (node, offset) => {
|
|
107
|
+
const isNumberColumnEnabled = node.attrs.isNumberColumnEnabled;
|
|
108
|
+
if (isNumberColumnEnabled && offset > 0) {
|
|
109
|
+
return getTableContainerWidth(node) - offset;
|
|
110
|
+
}
|
|
111
|
+
return getTableContainerWidth(node);
|
|
105
112
|
};
|
|
@@ -8,7 +8,7 @@ import { themed } from '@atlaskit/theme/components';
|
|
|
8
8
|
import { borderRadius } from '@atlaskit/theme/constants';
|
|
9
9
|
import Layer from '../Layer';
|
|
10
10
|
const packageName = "@atlaskit/editor-common";
|
|
11
|
-
const packageVersion = "74.
|
|
11
|
+
const packageVersion = "74.31.0";
|
|
12
12
|
const halfFocusRing = 1;
|
|
13
13
|
const dropOffset = '0, 8';
|
|
14
14
|
class DropList extends Component {
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
import { GapCursorSelection } from '../selection';
|
|
3
|
+
import { isEmptyParagraph } from './editor-core-utils';
|
|
4
|
+
const filter = (predicates, cmd) => {
|
|
2
5
|
return function (state, dispatch, view) {
|
|
3
6
|
if (!Array.isArray(predicates)) {
|
|
4
7
|
predicates = [predicates];
|
|
@@ -8,4 +11,105 @@ export const filter = (predicates, cmd) => {
|
|
|
8
11
|
}
|
|
9
12
|
return cmd(state, dispatch, view) || false;
|
|
10
13
|
};
|
|
11
|
-
};
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Walk forwards from a position until we encounter the (inside) start of
|
|
18
|
+
* the next node, or reach the end of the document.
|
|
19
|
+
*
|
|
20
|
+
* @param $startPos Position to start walking from.
|
|
21
|
+
*/
|
|
22
|
+
export const walkNextNode = $startPos => {
|
|
23
|
+
let $pos = $startPos;
|
|
24
|
+
|
|
25
|
+
// invariant 1: don't walk past the end of the document
|
|
26
|
+
// invariant 2: we are at the beginning or
|
|
27
|
+
// we haven't walked to the start of *any* node
|
|
28
|
+
// parentOffset includes textOffset.
|
|
29
|
+
while ($pos.pos < $pos.doc.nodeSize - 2 && ($pos.pos === $startPos.pos || $pos.parentOffset > 0)) {
|
|
30
|
+
$pos = $pos.doc.resolve($pos.pos + 1);
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
$pos: $pos,
|
|
34
|
+
foundNode: $pos.pos < $pos.doc.nodeSize - 2
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Walk backwards from a position until we encounter the (inside) end of
|
|
40
|
+
* the previous node, or reach the start of the document.
|
|
41
|
+
*
|
|
42
|
+
* @param $startPos Position to start walking from.
|
|
43
|
+
*/
|
|
44
|
+
export const walkPrevNode = $startPos => {
|
|
45
|
+
let $pos = $startPos;
|
|
46
|
+
while ($pos.pos > 0 && ($pos.pos === $startPos.pos || $pos.parentOffset < $pos.parent.nodeSize - 2)) {
|
|
47
|
+
$pos = $pos.doc.resolve($pos.pos - 1);
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
$pos: $pos,
|
|
51
|
+
foundNode: $pos.pos > 0
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* If the selection is empty, is inside a paragraph node and `canNextNodeMoveUp` is true then delete current paragraph
|
|
57
|
+
* and move the node below it up. The selection will be retained, to be placed in the moved node.
|
|
58
|
+
*
|
|
59
|
+
* @param canNextNodeMoveUp check if node directly after the selection is able to be brought up to selection
|
|
60
|
+
* @returns PM Command
|
|
61
|
+
*/
|
|
62
|
+
export const deleteEmptyParagraphAndMoveBlockUp = canNextNodeMoveUp => {
|
|
63
|
+
return (state, dispatch, view) => {
|
|
64
|
+
const {
|
|
65
|
+
selection: {
|
|
66
|
+
$from: {
|
|
67
|
+
pos,
|
|
68
|
+
parent
|
|
69
|
+
},
|
|
70
|
+
$head,
|
|
71
|
+
empty
|
|
72
|
+
},
|
|
73
|
+
tr,
|
|
74
|
+
doc
|
|
75
|
+
} = state;
|
|
76
|
+
const {
|
|
77
|
+
$pos
|
|
78
|
+
} = walkNextNode($head);
|
|
79
|
+
const nextPMNode = doc.nodeAt($pos.pos - 1);
|
|
80
|
+
if (empty && nextPMNode && canNextNodeMoveUp(nextPMNode) && isEmptyParagraph(parent) && view !== null && view !== void 0 && view.endOfTextblock('right')) {
|
|
81
|
+
tr.deleteRange(pos - 1, pos + 1);
|
|
82
|
+
if (dispatch) {
|
|
83
|
+
dispatch(tr);
|
|
84
|
+
}
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
export const insertContentDeleteRange = (tr, getSelectionResolvedPos, insertions, deletions) => {
|
|
91
|
+
insertions.forEach(contentInsert => {
|
|
92
|
+
let [content, pos] = contentInsert;
|
|
93
|
+
tr.insert(tr.mapping.map(pos), content);
|
|
94
|
+
});
|
|
95
|
+
deletions.forEach(deleteRange => {
|
|
96
|
+
let [firstPos, lastPos] = deleteRange;
|
|
97
|
+
tr.delete(tr.mapping.map(firstPos), tr.mapping.map(lastPos));
|
|
98
|
+
});
|
|
99
|
+
tr.setSelection(new TextSelection(getSelectionResolvedPos(tr)));
|
|
100
|
+
};
|
|
101
|
+
export const isEmptySelectionAtStart = state => {
|
|
102
|
+
const {
|
|
103
|
+
empty,
|
|
104
|
+
$from
|
|
105
|
+
} = state.selection;
|
|
106
|
+
return empty && ($from.parentOffset === 0 || state.selection instanceof GapCursorSelection);
|
|
107
|
+
};
|
|
108
|
+
export const isEmptySelectionAtEnd = state => {
|
|
109
|
+
const {
|
|
110
|
+
empty,
|
|
111
|
+
$from
|
|
112
|
+
} = state.selection;
|
|
113
|
+
return empty && ($from.end() === $from.pos || state.selection instanceof GapCursorSelection);
|
|
114
|
+
};
|
|
115
|
+
export { filter as filterCommand };
|
|
@@ -250,4 +250,28 @@ const maySanitizePrivateContent = (entity, providerFactory, sanitizePrivateConte
|
|
|
250
250
|
return sanitizeNodeForPrivacy(entity, providerFactory);
|
|
251
251
|
}
|
|
252
252
|
return entity;
|
|
253
|
-
};
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Returns false if node contains only empty inline nodes and hardBreaks.
|
|
257
|
+
*/
|
|
258
|
+
export function hasVisibleContent(node) {
|
|
259
|
+
const isInlineNodeHasVisibleContent = inlineNode => {
|
|
260
|
+
return inlineNode.isText ? !!inlineNode.textContent.trim() : inlineNode.type.name !== 'hardBreak';
|
|
261
|
+
};
|
|
262
|
+
if (node.isInline) {
|
|
263
|
+
return isInlineNodeHasVisibleContent(node);
|
|
264
|
+
} else if (node.isBlock && (node.isLeaf || node.isAtom)) {
|
|
265
|
+
return true;
|
|
266
|
+
} else if (!node.childCount) {
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
for (let index = 0; index < node.childCount; index++) {
|
|
270
|
+
const child = node.child(index);
|
|
271
|
+
const invisibleNodeTypes = ['paragraph', 'text', 'hardBreak'];
|
|
272
|
+
if (!invisibleNodeTypes.includes(child.type.name) || hasVisibleContent(child)) {
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
@@ -33,6 +33,7 @@ export { validateADFEntity, validationErrorHandler } from './validate-using-spec
|
|
|
33
33
|
export { getShallowPropsDifference, getPropsDifference } from './compare-props';
|
|
34
34
|
export { useComponentRenderTracking } from './performance/hooks/use-component-render-tracking';
|
|
35
35
|
export { isOutdatedBrowser } from './outdated-browsers';
|
|
36
|
+
export { autoJoinTr } from './prosemirror/autojoin';
|
|
36
37
|
export { isReferencedSource, removeConnectedNodes, getChildrenInfo, getNodeName } from './referentiality';
|
|
37
38
|
export { getItemCounterDigitsSize, getOrderFromOrderedListNode, resolveOrder, isListNode, isParagraphNode, isListItemNode, isBulletList } from './list';
|
|
38
39
|
export { isFromCurrentDomain, LinkMatcher, normalizeUrl, linkifyContent, getLinkDomain, findFilepaths, isLinkInMatches, FILEPATH_REGEXP, DONTLINKIFY_REGEXP, getLinkCreationAnalyticsEvent, canLinkBeCreatedInRange } from './hyperlink';
|
|
@@ -40,11 +41,11 @@ export { isFromCurrentDomain, LinkMatcher, normalizeUrl, linkifyContent, getLink
|
|
|
40
41
|
// prosemirror-history does not export its plugin key
|
|
41
42
|
export const pmHistoryPluginKey = 'history$';
|
|
42
43
|
export { gridTypeForLayout } from './grid';
|
|
43
|
-
export { nodesBetweenChanged, getStepRange, isEmptyDocument, processRawValue, hasDocAsParent, bracketTyped } from './document';
|
|
44
|
+
export { nodesBetweenChanged, getStepRange, isEmptyDocument, processRawValue, hasDocAsParent, bracketTyped, hasVisibleContent } from './document';
|
|
44
45
|
export { floatingLayouts, isRichMediaInsideOfBlockNode, calculateSnapPoints, alignAttributes } from './rich-media-utils';
|
|
45
46
|
export { sanitizeNodeForPrivacy } from './filter/privacy-filter';
|
|
46
47
|
export { canRenderDatasource } from './datasource';
|
|
47
|
-
export {
|
|
48
|
+
export { filterCommand, walkPrevNode, walkNextNode, isEmptySelectionAtStart, isEmptySelectionAtEnd, insertContentDeleteRange, deleteEmptyParagraphAndMoveBlockUp } from './commands';
|
|
48
49
|
export function shallowEqual(obj1 = {}, obj2 = {}) {
|
|
49
50
|
const keys1 = Object.keys(obj1);
|
|
50
51
|
const keys2 = Object.keys(obj2);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { canJoin } from '@atlaskit/editor-prosemirror/transform';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Checks whether two adjacent nodes can be joined. If so, the document
|
|
5
|
+
* will be updated to join those nodes. If not, the original transaction
|
|
6
|
+
* remains untouched.
|
|
7
|
+
*
|
|
8
|
+
* Nodes are considered joinable if the `isJoinable` predicate returns true or,
|
|
9
|
+
* if an array of strings was passed, if their node type name is in that array.
|
|
10
|
+
*
|
|
11
|
+
* Adapted from https://github.com/ProseMirror/prosemirror-commands/blob/master/src/commands.js#L597-L610
|
|
12
|
+
*/
|
|
13
|
+
export function autoJoinTr(tr, isJoinable) {
|
|
14
|
+
if (Array.isArray(isJoinable)) {
|
|
15
|
+
let types = isJoinable;
|
|
16
|
+
isJoinable = node => types.indexOf(node.type.name) > -1;
|
|
17
|
+
}
|
|
18
|
+
const ranges = [];
|
|
19
|
+
for (let i = 0; i < tr.mapping.maps.length; i++) {
|
|
20
|
+
const map = tr.mapping.maps[i];
|
|
21
|
+
for (let j = 0; j < ranges.length; j++) {
|
|
22
|
+
ranges[j] = map.map(ranges[j]);
|
|
23
|
+
}
|
|
24
|
+
map.forEach((_s, _e, from, to) => ranges.push(from, to));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Figure out which joinable points exist inside those ranges,
|
|
28
|
+
// by checking all node boundaries in their parent nodes.
|
|
29
|
+
const joinable = [];
|
|
30
|
+
for (let i = 0; i < ranges.length; i += 2) {
|
|
31
|
+
const from = ranges[i];
|
|
32
|
+
const to = ranges[i + 1];
|
|
33
|
+
const $from = tr.doc.resolve(from);
|
|
34
|
+
const depth = $from.sharedDepth(to);
|
|
35
|
+
const parent = $from.node(depth);
|
|
36
|
+
for (let index = $from.indexAfter(depth), pos = $from.after(depth + 1); pos <= to; ++index) {
|
|
37
|
+
const after = parent.maybeChild(index);
|
|
38
|
+
if (!after) {
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
if (index && joinable.indexOf(pos) === -1) {
|
|
42
|
+
const before = parent.child(index - 1);
|
|
43
|
+
if (before.type === after.type && isJoinable(before, after)) {
|
|
44
|
+
joinable.push(pos);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
pos += after.nodeSize;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Join the joinable points
|
|
51
|
+
joinable.sort((a, b) => a - b);
|
|
52
|
+
for (let i = joinable.length - 1; i >= 0; i--) {
|
|
53
|
+
if (canJoin(tr.doc, joinable[i])) {
|
|
54
|
+
tr.join(joinable[i]);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
package/dist/es2019/version.json
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { isListItemNode, isListNode } from '../utils';
|
|
2
|
+
import { getListItemAttributes } from './selection';
|
|
3
|
+
export var getCommonListAnalyticsAttributes = function getCommonListAnalyticsAttributes(state) {
|
|
4
|
+
var _state$selection = state.selection,
|
|
5
|
+
$from = _state$selection.$from,
|
|
6
|
+
$to = _state$selection.$to;
|
|
7
|
+
var fromAttrs = getListItemAttributes($from);
|
|
8
|
+
var toAttrs = getListItemAttributes($to);
|
|
9
|
+
return {
|
|
10
|
+
itemIndexAtSelectionStart: fromAttrs.itemIndex,
|
|
11
|
+
itemIndexAtSelectionEnd: toAttrs.itemIndex,
|
|
12
|
+
indentLevelAtSelectionStart: fromAttrs.indentLevel,
|
|
13
|
+
indentLevelAtSelectionEnd: toAttrs.indentLevel,
|
|
14
|
+
itemsInSelection: countListItemsInSelection(state)
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export var countListItemsInSelection = function countListItemsInSelection(state) {
|
|
18
|
+
var _state$selection2 = state.selection,
|
|
19
|
+
from = _state$selection2.from,
|
|
20
|
+
to = _state$selection2.to;
|
|
21
|
+
if (from === to) {
|
|
22
|
+
return 1;
|
|
23
|
+
}
|
|
24
|
+
var count = 0;
|
|
25
|
+
var listSlice = state.doc.cut(from, to);
|
|
26
|
+
listSlice.content.nodesBetween(0, listSlice.content.size, function (node, pos, parent, index) {
|
|
27
|
+
if (parent && isListItemNode(parent) && !isListNode(node) && index === 0) {
|
|
28
|
+
count++;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
return count;
|
|
32
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { numberNestedLists } from './selection';
|
|
2
|
+
export var hasValidListIndentationLevel = function hasValidListIndentationLevel(_ref) {
|
|
3
|
+
var tr = _ref.tr,
|
|
4
|
+
maxIndentation = _ref.maxIndentation;
|
|
5
|
+
var initialIndentationLevel = numberNestedLists(tr.selection.$from);
|
|
6
|
+
var currentIndentationLevel;
|
|
7
|
+
var currentPos = tr.selection.$to.pos;
|
|
8
|
+
do {
|
|
9
|
+
var resolvedPos = tr.doc.resolve(currentPos);
|
|
10
|
+
currentIndentationLevel = numberNestedLists(resolvedPos);
|
|
11
|
+
if (currentIndentationLevel > maxIndentation) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
currentPos++;
|
|
15
|
+
} while (currentIndentationLevel >= initialIndentationLevel);
|
|
16
|
+
return true;
|
|
17
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { getListItemAttributes, normalizeListItemsSelection } from './selection';
|
|
2
|
+
export { moveTargetIntoList } from './replace-content';
|
|
3
|
+
export { JoinDirection, isListNodeValidContent, joinSiblingLists } from './node';
|
|
4
|
+
export { getCommonListAnalyticsAttributes, countListItemsInSelection } from './analytics';
|
|
5
|
+
export { hasValidListIndentationLevel } from './indentation';
|
|
6
|
+
export { isListNode, isListItemNode, isBulletList, isParagraphNode } from '../utils';
|