@atlaskit/editor-common 74.33.0 → 74.34.1
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 +16 -0
- package/dist/cjs/keymaps/index.js +8 -1
- package/dist/cjs/keymaps/keymap.js +38 -0
- package/dist/cjs/monitoring/error.js +1 -1
- package/dist/cjs/ui/DropList/index.js +1 -1
- package/dist/cjs/utils/commands.js +180 -15
- package/dist/cjs/utils/editor-core-utils.js +53 -3
- package/dist/cjs/utils/index.js +48 -0
- package/dist/cjs/utils/input-rules.js +48 -2
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/keymaps/index.js +3 -2
- package/dist/es2019/keymaps/keymap.js +33 -0
- package/dist/es2019/monitoring/error.js +1 -1
- package/dist/es2019/ui/DropList/index.js +1 -1
- package/dist/es2019/utils/commands.js +173 -2
- package/dist/es2019/utils/editor-core-utils.js +46 -1
- package/dist/es2019/utils/index.js +3 -3
- package/dist/es2019/utils/input-rules.js +45 -0
- package/dist/es2019/version.json +1 -1
- package/dist/esm/keymaps/index.js +3 -2
- package/dist/esm/keymaps/keymap.js +33 -0
- package/dist/esm/monitoring/error.js +1 -1
- package/dist/esm/ui/DropList/index.js +1 -1
- package/dist/esm/utils/commands.js +170 -14
- package/dist/esm/utils/editor-core-utils.js +47 -0
- package/dist/esm/utils/index.js +3 -3
- package/dist/esm/utils/input-rules.js +44 -0
- package/dist/esm/version.json +1 -1
- package/dist/types/keymaps/index.d.ts +1 -0
- package/dist/types/keymaps/keymap.d.ts +11 -0
- package/dist/types/types/block-type.d.ts +1 -0
- package/dist/types/types/feature-flags.d.ts +0 -18
- package/dist/types/types/index.d.ts +1 -1
- package/dist/types/types/input-rules.d.ts +1 -1
- package/dist/types/utils/commands.d.ts +11 -5
- package/dist/types/utils/editor-core-utils.d.ts +7 -2
- package/dist/types/utils/index.d.ts +3 -3
- package/dist/types/utils/input-rules.d.ts +12 -4
- package/dist/types-ts4.5/keymaps/index.d.ts +1 -0
- package/dist/types-ts4.5/keymaps/keymap.d.ts +11 -0
- package/dist/types-ts4.5/types/block-type.d.ts +1 -0
- package/dist/types-ts4.5/types/feature-flags.d.ts +0 -18
- package/dist/types-ts4.5/types/index.d.ts +1 -1
- package/dist/types-ts4.5/types/input-rules.d.ts +1 -1
- package/dist/types-ts4.5/utils/commands.d.ts +11 -5
- package/dist/types-ts4.5/utils/editor-core-utils.d.ts +7 -2
- package/dist/types-ts4.5/utils/index.d.ts +3 -3
- package/dist/types-ts4.5/utils/input-rules.d.ts +12 -4
- package/package.json +5 -4
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
+
import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
3
|
+
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '../analytics';
|
|
4
|
+
import { withAnalytics } from '../editor-analytics';
|
|
2
5
|
import { GapCursorSelection } from '../selection';
|
|
3
6
|
import { isEmptyParagraph } from './editor-core-utils';
|
|
4
|
-
|
|
7
|
+
import { isMediaNode } from './nodes';
|
|
8
|
+
export const filter = (predicates, cmd) => {
|
|
5
9
|
return function (state, dispatch, view) {
|
|
6
10
|
if (!Array.isArray(predicates)) {
|
|
7
11
|
predicates = [predicates];
|
|
@@ -51,6 +55,173 @@ export const walkPrevNode = $startPos => {
|
|
|
51
55
|
foundNode: $pos.pos > 0
|
|
52
56
|
};
|
|
53
57
|
};
|
|
58
|
+
export function insertNewLine() {
|
|
59
|
+
return function (state, dispatch) {
|
|
60
|
+
const {
|
|
61
|
+
$from
|
|
62
|
+
} = state.selection;
|
|
63
|
+
const parent = $from.parent;
|
|
64
|
+
const {
|
|
65
|
+
hardBreak
|
|
66
|
+
} = state.schema.nodes;
|
|
67
|
+
if (hardBreak) {
|
|
68
|
+
const hardBreakNode = hardBreak.createChecked();
|
|
69
|
+
if (parent && parent.type.validContent(Fragment.from(hardBreakNode))) {
|
|
70
|
+
if (dispatch) {
|
|
71
|
+
dispatch(state.tr.replaceSelectionWith(hardBreakNode, false));
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (state.selection instanceof TextSelection) {
|
|
77
|
+
if (dispatch) {
|
|
78
|
+
dispatch(state.tr.insertText('\n'));
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
return false;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
export const insertNewLineWithAnalytics = editorAnalyticsAPI => withAnalytics(editorAnalyticsAPI, {
|
|
86
|
+
action: ACTION.INSERTED,
|
|
87
|
+
actionSubject: ACTION_SUBJECT.TEXT,
|
|
88
|
+
actionSubjectId: ACTION_SUBJECT_ID.LINE_BREAK,
|
|
89
|
+
eventType: EVENT_TYPE.TRACK
|
|
90
|
+
})(insertNewLine());
|
|
91
|
+
export const createNewParagraphAbove = (state, dispatch) => {
|
|
92
|
+
const append = false;
|
|
93
|
+
if (!canMoveUp(state) && canCreateParagraphNear(state)) {
|
|
94
|
+
createParagraphNear(append)(state, dispatch);
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
return false;
|
|
98
|
+
};
|
|
99
|
+
export const createNewParagraphBelow = (state, dispatch) => {
|
|
100
|
+
const append = true;
|
|
101
|
+
if (!canMoveDown(state) && canCreateParagraphNear(state)) {
|
|
102
|
+
createParagraphNear(append)(state, dispatch);
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
};
|
|
107
|
+
function canCreateParagraphNear(state) {
|
|
108
|
+
const {
|
|
109
|
+
selection: {
|
|
110
|
+
$from
|
|
111
|
+
}
|
|
112
|
+
} = state;
|
|
113
|
+
const node = $from.node($from.depth);
|
|
114
|
+
const insideCodeBlock = !!node && node.type === state.schema.nodes.codeBlock;
|
|
115
|
+
const isNodeSelection = state.selection instanceof NodeSelection;
|
|
116
|
+
return $from.depth > 1 || isNodeSelection || insideCodeBlock;
|
|
117
|
+
}
|
|
118
|
+
export function createParagraphNear(append = true) {
|
|
119
|
+
return function (state, dispatch) {
|
|
120
|
+
const paragraph = state.schema.nodes.paragraph;
|
|
121
|
+
if (!paragraph) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
let insertPos;
|
|
125
|
+
if (state.selection instanceof TextSelection) {
|
|
126
|
+
if (topLevelNodeIsEmptyTextBlock(state)) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
insertPos = getInsertPosFromTextBlock(state, append);
|
|
130
|
+
} else {
|
|
131
|
+
insertPos = getInsertPosFromNonTextBlock(state, append);
|
|
132
|
+
}
|
|
133
|
+
const tr = state.tr.insert(insertPos, paragraph.createAndFill());
|
|
134
|
+
tr.setSelection(TextSelection.create(tr.doc, insertPos + 1));
|
|
135
|
+
if (dispatch) {
|
|
136
|
+
dispatch(tr);
|
|
137
|
+
}
|
|
138
|
+
return true;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function getInsertPosFromTextBlock(state, append) {
|
|
142
|
+
const {
|
|
143
|
+
$from,
|
|
144
|
+
$to
|
|
145
|
+
} = state.selection;
|
|
146
|
+
let pos;
|
|
147
|
+
if (!append) {
|
|
148
|
+
pos = $from.start(0);
|
|
149
|
+
} else {
|
|
150
|
+
pos = $to.end(0);
|
|
151
|
+
}
|
|
152
|
+
return pos;
|
|
153
|
+
}
|
|
154
|
+
function getInsertPosFromNonTextBlock(state, append) {
|
|
155
|
+
const {
|
|
156
|
+
$from,
|
|
157
|
+
$to
|
|
158
|
+
} = state.selection;
|
|
159
|
+
const nodeAtSelection = state.selection instanceof NodeSelection && state.doc.nodeAt(state.selection.$anchor.pos);
|
|
160
|
+
const isMediaSelection = nodeAtSelection && nodeAtSelection.type.name === 'mediaGroup';
|
|
161
|
+
let pos;
|
|
162
|
+
if (!append) {
|
|
163
|
+
// The start position is different with text block because it starts from 0
|
|
164
|
+
pos = $from.start($from.depth);
|
|
165
|
+
// The depth is different with text block because it starts from 0
|
|
166
|
+
pos = $from.depth > 0 && !isMediaSelection ? pos - 1 : pos;
|
|
167
|
+
} else {
|
|
168
|
+
pos = $to.end($to.depth);
|
|
169
|
+
pos = $to.depth > 0 && !isMediaSelection ? pos + 1 : pos;
|
|
170
|
+
}
|
|
171
|
+
return pos;
|
|
172
|
+
}
|
|
173
|
+
function topLevelNodeIsEmptyTextBlock(state) {
|
|
174
|
+
const topLevelNode = state.selection.$from.node(1);
|
|
175
|
+
return topLevelNode.isTextblock && topLevelNode.type !== state.schema.nodes.codeBlock && topLevelNode.nodeSize === 2;
|
|
176
|
+
}
|
|
177
|
+
function canMoveUp(state) {
|
|
178
|
+
const {
|
|
179
|
+
selection
|
|
180
|
+
} = state;
|
|
181
|
+
/**
|
|
182
|
+
* If there's a media element on the selection it will use a gap cursor to move
|
|
183
|
+
*/
|
|
184
|
+
if (selection instanceof NodeSelection && isMediaNode(selection.node)) {
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
if (selection instanceof TextSelection) {
|
|
188
|
+
if (!selection.empty) {
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return !atTheBeginningOfDoc(state);
|
|
193
|
+
}
|
|
194
|
+
function canMoveDown(state) {
|
|
195
|
+
const {
|
|
196
|
+
selection
|
|
197
|
+
} = state;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* If there's a media element on the selection it will use a gap cursor to move
|
|
201
|
+
*/
|
|
202
|
+
if (selection instanceof NodeSelection && isMediaNode(selection.node)) {
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
if (selection instanceof TextSelection) {
|
|
206
|
+
if (!selection.empty) {
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return !atTheEndOfDoc(state);
|
|
211
|
+
}
|
|
212
|
+
export function atTheEndOfDoc(state) {
|
|
213
|
+
const {
|
|
214
|
+
selection,
|
|
215
|
+
doc
|
|
216
|
+
} = state;
|
|
217
|
+
return doc.nodeSize - selection.$to.pos - 2 === selection.$to.depth;
|
|
218
|
+
}
|
|
219
|
+
export function atTheBeginningOfDoc(state) {
|
|
220
|
+
const {
|
|
221
|
+
selection
|
|
222
|
+
} = state;
|
|
223
|
+
return selection.$from.pos === selection.$from.depth;
|
|
224
|
+
}
|
|
54
225
|
|
|
55
226
|
/**
|
|
56
227
|
* If the selection is empty, is inside a paragraph node and `canNextNodeMoveUp` is true then delete current paragraph
|
|
@@ -85,4 +85,49 @@ export const isValidPosition = (pos, state) => {
|
|
|
85
85
|
};
|
|
86
86
|
export const isInLayoutColumn = state => {
|
|
87
87
|
return hasParentNodeOfType(state.schema.nodes.layoutSection)(state.selection);
|
|
88
|
-
};
|
|
88
|
+
};
|
|
89
|
+
export function filterChildrenBetween(doc, from, to, predicate) {
|
|
90
|
+
const results = [];
|
|
91
|
+
doc.nodesBetween(from, to, (node, pos, parent) => {
|
|
92
|
+
if (predicate(node, pos, parent)) {
|
|
93
|
+
results.push({
|
|
94
|
+
node,
|
|
95
|
+
pos
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
return results;
|
|
100
|
+
}
|
|
101
|
+
export const removeBlockMarks = (state, marks) => {
|
|
102
|
+
const {
|
|
103
|
+
selection,
|
|
104
|
+
schema
|
|
105
|
+
} = state;
|
|
106
|
+
let {
|
|
107
|
+
tr
|
|
108
|
+
} = state;
|
|
109
|
+
|
|
110
|
+
// Marks might not exist in Schema
|
|
111
|
+
const marksToRemove = marks.filter(Boolean);
|
|
112
|
+
if (marksToRemove.length === 0) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Saves an extra dispatch */
|
|
117
|
+
let blockMarksExists = false;
|
|
118
|
+
const hasMark = mark => marksToRemove.indexOf(mark.type) > -1;
|
|
119
|
+
/**
|
|
120
|
+
* When you need to toggle the selection
|
|
121
|
+
* when another type which does not allow alignment is applied
|
|
122
|
+
*/
|
|
123
|
+
state.doc.nodesBetween(selection.from, selection.to, (node, pos) => {
|
|
124
|
+
if (node.type === schema.nodes.paragraph && node.marks.some(hasMark)) {
|
|
125
|
+
blockMarksExists = true;
|
|
126
|
+
const resolvedPos = state.doc.resolve(pos);
|
|
127
|
+
const withoutBlockMarks = node.marks.filter(not(hasMark));
|
|
128
|
+
tr = tr.setNodeMarkup(resolvedPos.pos, undefined, node.attrs, withoutBlockMarks);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
return blockMarksExists ? tr : undefined;
|
|
132
|
+
};
|
|
133
|
+
const not = fn => arg => !fn(arg);
|
|
@@ -3,7 +3,7 @@ export { getExtensionLozengeData } from './macro';
|
|
|
3
3
|
export { default as browser } from './browser';
|
|
4
4
|
export { default as ErrorReporter } from './error-reporter';
|
|
5
5
|
export { isPastDate, timestampToIsoFormat, timestampToString, timestampToTaskContext, timestampToUTCDate, todayTimestampInUTC } from './date';
|
|
6
|
-
export { isElementInTableCell, isTextSelection, isLastItemMediaGroup, setNodeSelection, setTextSelection, nonNullable, stepAddsOneOf, stepHasSlice, extractSliceFromStep, isValidPosition, isEmptyParagraph, isInLayoutColumn } from './editor-core-utils';
|
|
6
|
+
export { isElementInTableCell, isTextSelection, isLastItemMediaGroup, setNodeSelection, setTextSelection, nonNullable, stepAddsOneOf, stepHasSlice, extractSliceFromStep, isValidPosition, isEmptyParagraph, isInLayoutColumn, removeBlockMarks, filterChildrenBetween } from './editor-core-utils';
|
|
7
7
|
export { withImageLoader } from './imageLoader';
|
|
8
8
|
export { absoluteBreakoutWidth, calcBreakoutWidth, calcWideWidth, breakoutConsts, calculateBreakoutStyles, calcBreakoutWidthPx, getNextBreakoutMode, getTitle } from './breakout';
|
|
9
9
|
export { findChangedNodesFromTransaction, validNode, validateNodes, isType, isParagraph, isText, isLinkMark, SelectedState, isNodeSelectedOrInRange, isSupportedInParent, isMediaNode, isNodeBeforeMediaNode } from './nodes';
|
|
@@ -45,10 +45,10 @@ export { nodesBetweenChanged, getStepRange, isEmptyDocument, processRawValue, ha
|
|
|
45
45
|
export { floatingLayouts, isRichMediaInsideOfBlockNode, calculateSnapPoints, alignAttributes, nonWrappedLayouts } from './rich-media-utils';
|
|
46
46
|
export { sanitizeNodeForPrivacy } from './filter/privacy-filter';
|
|
47
47
|
export { canRenderDatasource } from './datasource';
|
|
48
|
-
export { filterCommand,
|
|
48
|
+
export { filterCommand, isEmptySelectionAtStart, isEmptySelectionAtEnd, insertContentDeleteRange, deleteEmptyParagraphAndMoveBlockUp, insertNewLineWithAnalytics, createNewParagraphAbove, createNewParagraphBelow, createParagraphNear, walkNextNode, walkPrevNode } from './commands';
|
|
49
49
|
export function shallowEqual(obj1 = {}, obj2 = {}) {
|
|
50
50
|
const keys1 = Object.keys(obj1);
|
|
51
51
|
const keys2 = Object.keys(obj2);
|
|
52
52
|
return keys1.length === keys2.length && keys1.reduce((acc, key) => acc && obj1[key] === obj2[key], true);
|
|
53
53
|
}
|
|
54
|
-
export { inputRuleWithAnalytics } from './input-rules';
|
|
54
|
+
export { inputRuleWithAnalytics, createWrappingJoinRule, createRule } from './input-rules';
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { closeHistory } from '@atlaskit/editor-prosemirror/history';
|
|
2
|
+
import { canJoin, findWrapping } from '@atlaskit/editor-prosemirror/transform';
|
|
3
|
+
import { JOIN_SCENARIOS_WHEN_TYPING_TO_INSERT_LIST } from '../analytics';
|
|
1
4
|
// Roughly based on atlassian-frontend/packages/editor/editor-core/src/utils/input-rules.ts but with the Editor Analytics API that's injected in plugins
|
|
2
5
|
export const inputRuleWithAnalytics = (getPayload, analyticsApi) => {
|
|
3
6
|
return originalRule => {
|
|
@@ -13,4 +16,46 @@ export const inputRuleWithAnalytics = (getPayload, analyticsApi) => {
|
|
|
13
16
|
onHandlerApply
|
|
14
17
|
};
|
|
15
18
|
};
|
|
19
|
+
};
|
|
20
|
+
export const createWrappingJoinRule = ({
|
|
21
|
+
match,
|
|
22
|
+
nodeType,
|
|
23
|
+
getAttrs,
|
|
24
|
+
joinPredicate
|
|
25
|
+
}) => {
|
|
26
|
+
const handler = (state, match, start, end) => {
|
|
27
|
+
const attrs = (getAttrs instanceof Function ? getAttrs(match) : getAttrs) || {};
|
|
28
|
+
const tr = state.tr;
|
|
29
|
+
const fixedStart = Math.max(start, 1);
|
|
30
|
+
tr.delete(fixedStart, end);
|
|
31
|
+
const $start = tr.doc.resolve(fixedStart);
|
|
32
|
+
const range = $start.blockRange();
|
|
33
|
+
const wrapping = range && findWrapping(range, nodeType, attrs);
|
|
34
|
+
if (!wrapping || !range) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const parentNodePosMapped = tr.mapping.map(range.start);
|
|
38
|
+
const parentNode = tr.doc.nodeAt(parentNodePosMapped);
|
|
39
|
+
const lastWrap = wrapping[wrapping.length - 1];
|
|
40
|
+
if (parentNode && lastWrap) {
|
|
41
|
+
const allowedMarks = lastWrap.type.allowedMarks(parentNode.marks) || [];
|
|
42
|
+
tr.setNodeMarkup(parentNodePosMapped, parentNode.type, parentNode.attrs, allowedMarks);
|
|
43
|
+
}
|
|
44
|
+
tr.wrap(range, wrapping);
|
|
45
|
+
const before = tr.doc.resolve(fixedStart - 1).nodeBefore;
|
|
46
|
+
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))) {
|
|
47
|
+
tr.join(fixedStart - 1);
|
|
48
|
+
}
|
|
49
|
+
return tr;
|
|
50
|
+
};
|
|
51
|
+
return createRule(match, handler);
|
|
52
|
+
};
|
|
53
|
+
export const createRule = (match, handler) => {
|
|
54
|
+
return {
|
|
55
|
+
match,
|
|
56
|
+
handler,
|
|
57
|
+
onHandlerApply: (_state, tr) => {
|
|
58
|
+
closeHistory(tr);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
16
61
|
};
|
package/dist/es2019/version.json
CHANGED
|
@@ -77,7 +77,7 @@ var arrowKeysMap = {
|
|
|
77
77
|
ARROWUP: "\u2191",
|
|
78
78
|
ARROWDOWN: "\u2193"
|
|
79
79
|
};
|
|
80
|
-
var tooltipShortcutStyle = css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n border-radius: 2px;\n background-color: ", ";\n padding: 0
|
|
80
|
+
var tooltipShortcutStyle = css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n border-radius: 2px;\n background-color: ", ";\n padding: 0 ", ";\n\n /* TODO: fix in develop: https://atlassian.slack.com/archives/CFG3PSQ9E/p1647395052443259?thread_ts=1647394572.556029&cid=CFG3PSQ9E */\n /* stylelint-disable-next-line */\n label: tooltip-shortcut;\n"])), "var(--ds-background-inverse-subtle, ".concat(N400, ")"), "var(--ds-space-025, 2px)");
|
|
81
81
|
/* eslint-enable @atlaskit/design-system/ensure-design-token-usage */
|
|
82
82
|
|
|
83
83
|
function formatShortcut(keymap) {
|
|
@@ -201,4 +201,5 @@ export function findKeyMapForBrowser(keyMap) {
|
|
|
201
201
|
}
|
|
202
202
|
return;
|
|
203
203
|
}
|
|
204
|
-
export { DOWN, HEADING_KEYS, KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, LEFT, RIGHT, UP } from './consts';
|
|
204
|
+
export { DOWN, HEADING_KEYS, KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, LEFT, RIGHT, UP } from './consts';
|
|
205
|
+
export { keymap } from './keymap';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { base, keyName } from 'w3c-keyname';
|
|
2
|
+
import { keydownHandler } from '@atlaskit/editor-prosemirror/keymap';
|
|
3
|
+
import { SafePlugin } from '../safe-plugin';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A workaround for mostly Cyrillic but should have a positive affect
|
|
7
|
+
* on other languages / layouts. Attempts a similar approach to OS X.
|
|
8
|
+
* @see ED-7310
|
|
9
|
+
* @see https://github.com/ProseMirror/prosemirror/issues/957
|
|
10
|
+
* @param bindings
|
|
11
|
+
*/
|
|
12
|
+
export function keymap(bindings) {
|
|
13
|
+
return new SafePlugin({
|
|
14
|
+
props: {
|
|
15
|
+
handleKeyDown: function handleKeyDown(view, event) {
|
|
16
|
+
var name = keyName(event);
|
|
17
|
+
var keyboardEvent = event;
|
|
18
|
+
if (event.ctrlKey && name.length === 1 &&
|
|
19
|
+
// Check the unicode of the character to
|
|
20
|
+
// assert that its not an ASCII character.
|
|
21
|
+
// These are characters outside Latin's range.
|
|
22
|
+
/[^\u0000-\u007f]/.test(name)) {
|
|
23
|
+
keyboardEvent = new KeyboardEvent('keydown', {
|
|
24
|
+
key: base[event.keyCode],
|
|
25
|
+
code: event.code,
|
|
26
|
+
ctrlKey: true
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return keydownHandler(bindings)(view, keyboardEvent);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -6,7 +6,7 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
|
|
|
6
6
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
7
7
|
var SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
|
|
8
8
|
var packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
|
|
9
|
-
var packageVersion = "74.
|
|
9
|
+
var packageVersion = "74.34.1";
|
|
10
10
|
var sanitiseSentryEvents = function sanitiseSentryEvents(data, _hint) {
|
|
11
11
|
// Remove URL as it has UGC
|
|
12
12
|
// TODO: Sanitise the URL instead of just removing it
|
|
@@ -18,7 +18,7 @@ import { themed } from '@atlaskit/theme/components';
|
|
|
18
18
|
import { borderRadius } from '@atlaskit/theme/constants';
|
|
19
19
|
import Layer from '../Layer';
|
|
20
20
|
var packageName = "@atlaskit/editor-common";
|
|
21
|
-
var packageVersion = "74.
|
|
21
|
+
var packageVersion = "74.34.1";
|
|
22
22
|
var halfFocusRing = 1;
|
|
23
23
|
var dropOffset = '0, 8';
|
|
24
24
|
var DropList = /*#__PURE__*/function (_Component) {
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
-
import {
|
|
2
|
+
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
3
|
+
import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
4
|
+
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '../analytics';
|
|
5
|
+
import { withAnalytics } from '../editor-analytics';
|
|
3
6
|
import { GapCursorSelection } from '../selection';
|
|
4
7
|
import { isEmptyParagraph } from './editor-core-utils';
|
|
5
|
-
|
|
8
|
+
import { isMediaNode } from './nodes';
|
|
9
|
+
export var filter = function filter(predicates, cmd) {
|
|
6
10
|
return function (state, dispatch, view) {
|
|
7
11
|
if (!Array.isArray(predicates)) {
|
|
8
12
|
predicates = [predicates];
|
|
@@ -54,6 +58,158 @@ export var walkPrevNode = function walkPrevNode($startPos) {
|
|
|
54
58
|
foundNode: $pos.pos > 0
|
|
55
59
|
};
|
|
56
60
|
};
|
|
61
|
+
export function insertNewLine() {
|
|
62
|
+
return function (state, dispatch) {
|
|
63
|
+
var $from = state.selection.$from;
|
|
64
|
+
var parent = $from.parent;
|
|
65
|
+
var hardBreak = state.schema.nodes.hardBreak;
|
|
66
|
+
if (hardBreak) {
|
|
67
|
+
var hardBreakNode = hardBreak.createChecked();
|
|
68
|
+
if (parent && parent.type.validContent(Fragment.from(hardBreakNode))) {
|
|
69
|
+
if (dispatch) {
|
|
70
|
+
dispatch(state.tr.replaceSelectionWith(hardBreakNode, false));
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (state.selection instanceof TextSelection) {
|
|
76
|
+
if (dispatch) {
|
|
77
|
+
dispatch(state.tr.insertText('\n'));
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
return false;
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export var insertNewLineWithAnalytics = function insertNewLineWithAnalytics(editorAnalyticsAPI) {
|
|
85
|
+
return withAnalytics(editorAnalyticsAPI, {
|
|
86
|
+
action: ACTION.INSERTED,
|
|
87
|
+
actionSubject: ACTION_SUBJECT.TEXT,
|
|
88
|
+
actionSubjectId: ACTION_SUBJECT_ID.LINE_BREAK,
|
|
89
|
+
eventType: EVENT_TYPE.TRACK
|
|
90
|
+
})(insertNewLine());
|
|
91
|
+
};
|
|
92
|
+
export var createNewParagraphAbove = function createNewParagraphAbove(state, dispatch) {
|
|
93
|
+
var append = false;
|
|
94
|
+
if (!canMoveUp(state) && canCreateParagraphNear(state)) {
|
|
95
|
+
createParagraphNear(append)(state, dispatch);
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
};
|
|
100
|
+
export var createNewParagraphBelow = function createNewParagraphBelow(state, dispatch) {
|
|
101
|
+
var append = true;
|
|
102
|
+
if (!canMoveDown(state) && canCreateParagraphNear(state)) {
|
|
103
|
+
createParagraphNear(append)(state, dispatch);
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
};
|
|
108
|
+
function canCreateParagraphNear(state) {
|
|
109
|
+
var $from = state.selection.$from;
|
|
110
|
+
var node = $from.node($from.depth);
|
|
111
|
+
var insideCodeBlock = !!node && node.type === state.schema.nodes.codeBlock;
|
|
112
|
+
var isNodeSelection = state.selection instanceof NodeSelection;
|
|
113
|
+
return $from.depth > 1 || isNodeSelection || insideCodeBlock;
|
|
114
|
+
}
|
|
115
|
+
export function createParagraphNear() {
|
|
116
|
+
var append = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
117
|
+
return function (state, dispatch) {
|
|
118
|
+
var paragraph = state.schema.nodes.paragraph;
|
|
119
|
+
if (!paragraph) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
var insertPos;
|
|
123
|
+
if (state.selection instanceof TextSelection) {
|
|
124
|
+
if (topLevelNodeIsEmptyTextBlock(state)) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
insertPos = getInsertPosFromTextBlock(state, append);
|
|
128
|
+
} else {
|
|
129
|
+
insertPos = getInsertPosFromNonTextBlock(state, append);
|
|
130
|
+
}
|
|
131
|
+
var tr = state.tr.insert(insertPos, paragraph.createAndFill());
|
|
132
|
+
tr.setSelection(TextSelection.create(tr.doc, insertPos + 1));
|
|
133
|
+
if (dispatch) {
|
|
134
|
+
dispatch(tr);
|
|
135
|
+
}
|
|
136
|
+
return true;
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function getInsertPosFromTextBlock(state, append) {
|
|
140
|
+
var _state$selection = state.selection,
|
|
141
|
+
$from = _state$selection.$from,
|
|
142
|
+
$to = _state$selection.$to;
|
|
143
|
+
var pos;
|
|
144
|
+
if (!append) {
|
|
145
|
+
pos = $from.start(0);
|
|
146
|
+
} else {
|
|
147
|
+
pos = $to.end(0);
|
|
148
|
+
}
|
|
149
|
+
return pos;
|
|
150
|
+
}
|
|
151
|
+
function getInsertPosFromNonTextBlock(state, append) {
|
|
152
|
+
var _state$selection2 = state.selection,
|
|
153
|
+
$from = _state$selection2.$from,
|
|
154
|
+
$to = _state$selection2.$to;
|
|
155
|
+
var nodeAtSelection = state.selection instanceof NodeSelection && state.doc.nodeAt(state.selection.$anchor.pos);
|
|
156
|
+
var isMediaSelection = nodeAtSelection && nodeAtSelection.type.name === 'mediaGroup';
|
|
157
|
+
var pos;
|
|
158
|
+
if (!append) {
|
|
159
|
+
// The start position is different with text block because it starts from 0
|
|
160
|
+
pos = $from.start($from.depth);
|
|
161
|
+
// The depth is different with text block because it starts from 0
|
|
162
|
+
pos = $from.depth > 0 && !isMediaSelection ? pos - 1 : pos;
|
|
163
|
+
} else {
|
|
164
|
+
pos = $to.end($to.depth);
|
|
165
|
+
pos = $to.depth > 0 && !isMediaSelection ? pos + 1 : pos;
|
|
166
|
+
}
|
|
167
|
+
return pos;
|
|
168
|
+
}
|
|
169
|
+
function topLevelNodeIsEmptyTextBlock(state) {
|
|
170
|
+
var topLevelNode = state.selection.$from.node(1);
|
|
171
|
+
return topLevelNode.isTextblock && topLevelNode.type !== state.schema.nodes.codeBlock && topLevelNode.nodeSize === 2;
|
|
172
|
+
}
|
|
173
|
+
function canMoveUp(state) {
|
|
174
|
+
var selection = state.selection;
|
|
175
|
+
/**
|
|
176
|
+
* If there's a media element on the selection it will use a gap cursor to move
|
|
177
|
+
*/
|
|
178
|
+
if (selection instanceof NodeSelection && isMediaNode(selection.node)) {
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
if (selection instanceof TextSelection) {
|
|
182
|
+
if (!selection.empty) {
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return !atTheBeginningOfDoc(state);
|
|
187
|
+
}
|
|
188
|
+
function canMoveDown(state) {
|
|
189
|
+
var selection = state.selection;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* If there's a media element on the selection it will use a gap cursor to move
|
|
193
|
+
*/
|
|
194
|
+
if (selection instanceof NodeSelection && isMediaNode(selection.node)) {
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
if (selection instanceof TextSelection) {
|
|
198
|
+
if (!selection.empty) {
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return !atTheEndOfDoc(state);
|
|
203
|
+
}
|
|
204
|
+
export function atTheEndOfDoc(state) {
|
|
205
|
+
var selection = state.selection,
|
|
206
|
+
doc = state.doc;
|
|
207
|
+
return doc.nodeSize - selection.$to.pos - 2 === selection.$to.depth;
|
|
208
|
+
}
|
|
209
|
+
export function atTheBeginningOfDoc(state) {
|
|
210
|
+
var selection = state.selection;
|
|
211
|
+
return selection.$from.pos === selection.$from.depth;
|
|
212
|
+
}
|
|
57
213
|
|
|
58
214
|
/**
|
|
59
215
|
* If the selection is empty, is inside a paragraph node and `canNextNodeMoveUp` is true then delete current paragraph
|
|
@@ -64,12 +220,12 @@ export var walkPrevNode = function walkPrevNode($startPos) {
|
|
|
64
220
|
*/
|
|
65
221
|
export var deleteEmptyParagraphAndMoveBlockUp = function deleteEmptyParagraphAndMoveBlockUp(canNextNodeMoveUp) {
|
|
66
222
|
return function (state, dispatch, view) {
|
|
67
|
-
var _state$
|
|
68
|
-
_state$
|
|
69
|
-
pos = _state$
|
|
70
|
-
parent = _state$
|
|
71
|
-
$head = _state$
|
|
72
|
-
empty = _state$
|
|
223
|
+
var _state$selection3 = state.selection,
|
|
224
|
+
_state$selection3$$fr = _state$selection3.$from,
|
|
225
|
+
pos = _state$selection3$$fr.pos,
|
|
226
|
+
parent = _state$selection3$$fr.parent,
|
|
227
|
+
$head = _state$selection3.$head,
|
|
228
|
+
empty = _state$selection3.empty,
|
|
73
229
|
tr = state.tr,
|
|
74
230
|
doc = state.doc;
|
|
75
231
|
var _walkNextNode = walkNextNode($head),
|
|
@@ -101,15 +257,15 @@ export var insertContentDeleteRange = function insertContentDeleteRange(tr, getS
|
|
|
101
257
|
tr.setSelection(new TextSelection(getSelectionResolvedPos(tr)));
|
|
102
258
|
};
|
|
103
259
|
export var isEmptySelectionAtStart = function isEmptySelectionAtStart(state) {
|
|
104
|
-
var _state$
|
|
105
|
-
empty = _state$
|
|
106
|
-
$from = _state$
|
|
260
|
+
var _state$selection4 = state.selection,
|
|
261
|
+
empty = _state$selection4.empty,
|
|
262
|
+
$from = _state$selection4.$from;
|
|
107
263
|
return empty && ($from.parentOffset === 0 || state.selection instanceof GapCursorSelection);
|
|
108
264
|
};
|
|
109
265
|
export var isEmptySelectionAtEnd = function isEmptySelectionAtEnd(state) {
|
|
110
|
-
var _state$
|
|
111
|
-
empty = _state$
|
|
112
|
-
$from = _state$
|
|
266
|
+
var _state$selection5 = state.selection,
|
|
267
|
+
empty = _state$selection5.empty,
|
|
268
|
+
$from = _state$selection5.$from;
|
|
113
269
|
return empty && ($from.end() === $from.pos || state.selection instanceof GapCursorSelection);
|
|
114
270
|
};
|
|
115
271
|
export { filter as filterCommand };
|
|
@@ -83,4 +83,51 @@ export var isValidPosition = function isValidPosition(pos, state) {
|
|
|
83
83
|
};
|
|
84
84
|
export var isInLayoutColumn = function isInLayoutColumn(state) {
|
|
85
85
|
return hasParentNodeOfType(state.schema.nodes.layoutSection)(state.selection);
|
|
86
|
+
};
|
|
87
|
+
export function filterChildrenBetween(doc, from, to, predicate) {
|
|
88
|
+
var results = [];
|
|
89
|
+
doc.nodesBetween(from, to, function (node, pos, parent) {
|
|
90
|
+
if (predicate(node, pos, parent)) {
|
|
91
|
+
results.push({
|
|
92
|
+
node: node,
|
|
93
|
+
pos: pos
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
return results;
|
|
98
|
+
}
|
|
99
|
+
export var removeBlockMarks = function removeBlockMarks(state, marks) {
|
|
100
|
+
var selection = state.selection,
|
|
101
|
+
schema = state.schema;
|
|
102
|
+
var tr = state.tr;
|
|
103
|
+
|
|
104
|
+
// Marks might not exist in Schema
|
|
105
|
+
var marksToRemove = marks.filter(Boolean);
|
|
106
|
+
if (marksToRemove.length === 0) {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Saves an extra dispatch */
|
|
111
|
+
var blockMarksExists = false;
|
|
112
|
+
var hasMark = function hasMark(mark) {
|
|
113
|
+
return marksToRemove.indexOf(mark.type) > -1;
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* When you need to toggle the selection
|
|
117
|
+
* when another type which does not allow alignment is applied
|
|
118
|
+
*/
|
|
119
|
+
state.doc.nodesBetween(selection.from, selection.to, function (node, pos) {
|
|
120
|
+
if (node.type === schema.nodes.paragraph && node.marks.some(hasMark)) {
|
|
121
|
+
blockMarksExists = true;
|
|
122
|
+
var resolvedPos = state.doc.resolve(pos);
|
|
123
|
+
var withoutBlockMarks = node.marks.filter(not(hasMark));
|
|
124
|
+
tr = tr.setNodeMarkup(resolvedPos.pos, undefined, node.attrs, withoutBlockMarks);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
return blockMarksExists ? tr : undefined;
|
|
128
|
+
};
|
|
129
|
+
var not = function not(fn) {
|
|
130
|
+
return function (arg) {
|
|
131
|
+
return !fn(arg);
|
|
132
|
+
};
|
|
86
133
|
};
|