@limetech/lime-elements 39.44.6 → 39.45.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 +14 -0
- package/dist/cjs/limel-markdown.cjs.entry.js +1 -1
- package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js +778 -395
- package/dist/cjs/{markdown-parser-ChnRAxpZ.js → markdown-parser-YH5HSSgF.js} +36 -56
- package/dist/collection/components/text-editor/prosemirror-adapter/editor-config.js +12 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/menu/menu-command-utils/active-state-utils.js +36 -0
- package/dist/collection/components/text-editor/prosemirror-adapter/menu/menu-command-utils/list-utils.js +270 -0
- package/dist/collection/components/text-editor/prosemirror-adapter/menu/menu-command-utils/node-utils.js +15 -0
- package/dist/collection/components/text-editor/prosemirror-adapter/menu/menu-commands.js +81 -69
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/list-key-handler.js +44 -0
- package/dist/collection/components/text-editor/prosemirror-adapter/prosemirror-adapter.js +4 -3
- package/dist/esm/limel-markdown.entry.js +1 -1
- package/dist/esm/limel-prosemirror-adapter.entry.js +779 -396
- package/dist/esm/{markdown-parser-BSQKleVw.js → markdown-parser-DrxxGLF5.js} +36 -56
- package/dist/lime-elements/lime-elements.esm.js +1 -1
- package/dist/lime-elements/p-1f29f482.entry.js +1 -0
- package/dist/lime-elements/{p-3ea159fd.entry.js → p-38393fb4.entry.js} +1 -1
- package/dist/lime-elements/{p-B0qhUema.js → p-C9xHOCE_.js} +2 -2
- package/dist/types/components/text-editor/prosemirror-adapter/menu/menu-command-utils/active-state-utils.d.ts +6 -0
- package/dist/types/components/text-editor/prosemirror-adapter/menu/menu-command-utils/list-utils.d.ts +68 -0
- package/dist/types/components/text-editor/prosemirror-adapter/menu/menu-command-utils/node-utils.d.ts +10 -0
- package/dist/types/components/text-editor/prosemirror-adapter/menu/menu-commands.d.ts +10 -0
- package/dist/types/components/text-editor/prosemirror-adapter/plugins/list-key-handler.d.ts +14 -0
- package/package.json +2 -2
- package/dist/lime-elements/p-845cfda7.entry.js +0 -1
|
@@ -33093,7 +33093,7 @@ function rehypeRaw(options) {
|
|
|
33093
33093
|
|
|
33094
33094
|
// http://www.w3.org/TR/CSS21/grammar.html
|
|
33095
33095
|
// https://github.com/visionmedia/css-parse/pull/49#issuecomment-30088027
|
|
33096
|
-
var COMMENT_REGEX = /\/\*[^*]
|
|
33096
|
+
var COMMENT_REGEX = /\/\*(?:[^*]|\*(?!\/))*\*\//g;
|
|
33097
33097
|
|
|
33098
33098
|
var NEWLINE_REGEX = /\n/g;
|
|
33099
33099
|
var WHITESPACE_REGEX = /^\s*/;
|
|
@@ -33101,12 +33101,10 @@ var WHITESPACE_REGEX = /^\s*/;
|
|
|
33101
33101
|
// declaration
|
|
33102
33102
|
var PROPERTY_REGEX = /^(\*?[-#/*\\\w]+(\[[0-9a-z_-]+\])?)\s*/;
|
|
33103
33103
|
var COLON_REGEX = /^:\s*/;
|
|
33104
|
-
var VALUE_REGEX =
|
|
33104
|
+
var VALUE_REGEX =
|
|
33105
|
+
/^((?:'(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"|url\((?:'(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"|[^)]*)\)|[^};])+)/;
|
|
33105
33106
|
var SEMICOLON_REGEX = /^[;\s]*/;
|
|
33106
33107
|
|
|
33107
|
-
// https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim#Polyfill
|
|
33108
|
-
var TRIM_REGEX = /^\s+|\s+$/g;
|
|
33109
|
-
|
|
33110
33108
|
// strings
|
|
33111
33109
|
var NEWLINE = '\n';
|
|
33112
33110
|
var FORWARD_SLASH = '/';
|
|
@@ -33230,16 +33228,13 @@ function index (style, options) {
|
|
|
33230
33228
|
/**
|
|
33231
33229
|
* Parse comments.
|
|
33232
33230
|
*
|
|
33233
|
-
* @param {Object[]}
|
|
33231
|
+
* @param {Object[]} rules
|
|
33234
33232
|
* @return {Object[]}
|
|
33235
33233
|
*/
|
|
33236
33234
|
function comments(rules) {
|
|
33237
33235
|
var c;
|
|
33238
|
-
rules = rules || [];
|
|
33239
33236
|
while ((c = comment())) {
|
|
33240
|
-
|
|
33241
|
-
rules.push(c);
|
|
33242
|
-
}
|
|
33237
|
+
rules.push(c);
|
|
33243
33238
|
}
|
|
33244
33239
|
return rules;
|
|
33245
33240
|
}
|
|
@@ -33301,9 +33296,9 @@ function index (style, options) {
|
|
|
33301
33296
|
|
|
33302
33297
|
var ret = pos({
|
|
33303
33298
|
type: TYPE_DECLARATION,
|
|
33304
|
-
property:
|
|
33299
|
+
property: prop[0].replace(COMMENT_REGEX, EMPTY_STRING).trim(),
|
|
33305
33300
|
value: val
|
|
33306
|
-
?
|
|
33301
|
+
? val[0].replace(COMMENT_REGEX, EMPTY_STRING).trim()
|
|
33307
33302
|
: EMPTY_STRING
|
|
33308
33303
|
});
|
|
33309
33304
|
|
|
@@ -33326,10 +33321,8 @@ function index (style, options) {
|
|
|
33326
33321
|
// declarations
|
|
33327
33322
|
var decl;
|
|
33328
33323
|
while ((decl = declaration())) {
|
|
33329
|
-
|
|
33330
|
-
|
|
33331
|
-
comments(decls);
|
|
33332
|
-
}
|
|
33324
|
+
decls.push(decl);
|
|
33325
|
+
comments(decls);
|
|
33333
33326
|
}
|
|
33334
33327
|
|
|
33335
33328
|
return decls;
|
|
@@ -33339,47 +33332,34 @@ function index (style, options) {
|
|
|
33339
33332
|
return declarations();
|
|
33340
33333
|
}
|
|
33341
33334
|
|
|
33342
|
-
|
|
33343
|
-
|
|
33344
|
-
|
|
33345
|
-
|
|
33346
|
-
|
|
33347
|
-
|
|
33348
|
-
|
|
33349
|
-
|
|
33350
|
-
|
|
33351
|
-
|
|
33352
|
-
|
|
33353
|
-
|
|
33354
|
-
|
|
33355
|
-
|
|
33356
|
-
|
|
33357
|
-
* @returns - Style object or null.
|
|
33358
|
-
*
|
|
33359
|
-
* @example Parsing inline style to object:
|
|
33360
|
-
*
|
|
33361
|
-
* ```js
|
|
33362
|
-
* import parse from 'style-to-object';
|
|
33363
|
-
* parse('line-height: 42;'); // { 'line-height': '42' }
|
|
33364
|
-
* ```
|
|
33365
|
-
*/
|
|
33335
|
+
//#region src/index.ts
|
|
33336
|
+
/**
|
|
33337
|
+
* Parses inline style to object.
|
|
33338
|
+
*
|
|
33339
|
+
* @param style - Inline style.
|
|
33340
|
+
* @param iterator - Iterator.
|
|
33341
|
+
* @returns - Style object or null.
|
|
33342
|
+
*
|
|
33343
|
+
* @example Parsing inline style to object:
|
|
33344
|
+
*
|
|
33345
|
+
* ```js
|
|
33346
|
+
* import parse from 'style-to-object';
|
|
33347
|
+
* parse('line-height: 42;'); // { 'line-height': '42' }
|
|
33348
|
+
* ```
|
|
33349
|
+
*/
|
|
33366
33350
|
function StyleToObject(style, iterator) {
|
|
33367
|
-
|
|
33368
|
-
|
|
33369
|
-
|
|
33370
|
-
|
|
33371
|
-
|
|
33372
|
-
|
|
33373
|
-
|
|
33374
|
-
|
|
33375
|
-
|
|
33376
|
-
|
|
33377
|
-
|
|
33378
|
-
|
|
33379
|
-
styleObject[property] = value;
|
|
33380
|
-
}
|
|
33381
|
-
});
|
|
33382
|
-
return styleObject;
|
|
33351
|
+
let styleObject = null;
|
|
33352
|
+
if (!style || typeof style !== "string") return styleObject;
|
|
33353
|
+
const declarations = index(style);
|
|
33354
|
+
declarations.forEach((declaration) => {
|
|
33355
|
+
if (declaration.type !== "declaration") return;
|
|
33356
|
+
const { property, value } = declaration;
|
|
33357
|
+
if (value) {
|
|
33358
|
+
styleObject = styleObject ?? {};
|
|
33359
|
+
styleObject[property] = value;
|
|
33360
|
+
}
|
|
33361
|
+
});
|
|
33362
|
+
return styleObject;
|
|
33383
33363
|
}
|
|
33384
33364
|
|
|
33385
33365
|
var colorName$1;
|
|
@@ -11,6 +11,7 @@ import { createImageInserterPlugin } from "./plugins/image/inserter";
|
|
|
11
11
|
import { createImageViewPlugin } from "./plugins/image/view";
|
|
12
12
|
import { createMenuStateTrackingPlugin } from "./plugins/menu-state-tracking-plugin";
|
|
13
13
|
import { createActionBarInteractionPlugin } from "./plugins/menu-action-interaction-plugin";
|
|
14
|
+
import { createListKeyHandlerPlugin } from "./plugins/list-key-handler";
|
|
14
15
|
import { createTriggerPlugin } from "./plugins/trigger/factory";
|
|
15
16
|
import { getTableNodes, getTableEditingPlugins } from "./plugins/table-plugin";
|
|
16
17
|
import { getImageNode } from "./plugins/image/node";
|
|
@@ -62,7 +63,16 @@ export function buildEditorSchema(options) {
|
|
|
62
63
|
export function buildEditorPlugins(options) {
|
|
63
64
|
const { schema, menuCommandFactory, contentConverter, language, contentType, triggerCharacters, inlineImages, onNewLinkSelection, onImagePasted, onActiveItemsChange, } = options;
|
|
64
65
|
return [
|
|
65
|
-
|
|
66
|
+
// exampleSetup binds Shift-Ctrl-8/9 to a plain wrapInList. On
|
|
67
|
+
// Windows/Linux those are the same physical keys as our
|
|
68
|
+
// Mod-Shift-8/7 list commands, and exampleSetup's keymap runs
|
|
69
|
+
// first, so its bindings are suppressed to let the context-aware
|
|
70
|
+
// list commands own the shortcuts on every platform.
|
|
71
|
+
...exampleSetup({
|
|
72
|
+
schema: schema,
|
|
73
|
+
menuBar: false,
|
|
74
|
+
mapKeys: { 'Shift-Ctrl-8': false, 'Shift-Ctrl-9': false },
|
|
75
|
+
}),
|
|
66
76
|
keymap(menuCommandFactory.buildKeymap()),
|
|
67
77
|
createTriggerPlugin(triggerCharacters, contentConverter),
|
|
68
78
|
createLinkPlugin(onNewLinkSelection),
|
|
@@ -70,6 +80,7 @@ export function buildEditorPlugins(options) {
|
|
|
70
80
|
createImageViewPlugin(language),
|
|
71
81
|
createMenuStateTrackingPlugin(editorMenuTypesArray, menuCommandFactory, onActiveItemsChange),
|
|
72
82
|
createActionBarInteractionPlugin(menuCommandFactory),
|
|
83
|
+
createListKeyHandlerPlugin(schema),
|
|
73
84
|
...getTableEditingPlugins(contentType === 'html'),
|
|
74
85
|
];
|
|
75
86
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { LevelMapping } from "../types";
|
|
2
|
+
export const setActiveMethodForMark = (command, markType) => {
|
|
3
|
+
command.active = (state) => {
|
|
4
|
+
const { from, $from, to, empty } = state.selection;
|
|
5
|
+
if (empty) {
|
|
6
|
+
return !!markType.isInSet(state.storedMarks || $from.marks());
|
|
7
|
+
}
|
|
8
|
+
return state.doc.rangeHasMark(from, to, markType);
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
export const setActiveMethodForNode = (command, nodeType, level) => {
|
|
12
|
+
command.active = (state) => {
|
|
13
|
+
const { $from } = state.selection;
|
|
14
|
+
const node = $from.node($from.depth);
|
|
15
|
+
if (node && node.type.name === nodeType.name) {
|
|
16
|
+
if (nodeType.name === LevelMapping.Heading && level) {
|
|
17
|
+
return node.attrs.level === level;
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
return false;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export const setActiveMethodForWrap = (command, nodeType) => {
|
|
25
|
+
command.active = (state) => {
|
|
26
|
+
const { from, to } = state.selection;
|
|
27
|
+
let found = false;
|
|
28
|
+
state.doc.nodesBetween(from, to, (node) => {
|
|
29
|
+
if (node.type === nodeType) {
|
|
30
|
+
found = true;
|
|
31
|
+
}
|
|
32
|
+
return !found;
|
|
33
|
+
});
|
|
34
|
+
return found;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s)
|
|
4
|
+
if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
import { NodeRange, } from "prosemirror-model";
|
|
14
|
+
import { canSplit, findWrapping } from "prosemirror-transform";
|
|
15
|
+
/**
|
|
16
|
+
* Whether the selection touches top-level blocks that cannot become list
|
|
17
|
+
* items (list_item requires a leading paragraph, so headings, blockquotes,
|
|
18
|
+
* code blocks and tables are not listable).
|
|
19
|
+
*
|
|
20
|
+
* @param state - the current editor state
|
|
21
|
+
* @returns true when a non-listable block intersects the selection
|
|
22
|
+
*/
|
|
23
|
+
export const selectionHasNonListableBlock = (state) => {
|
|
24
|
+
const { from, to } = state.selection;
|
|
25
|
+
const { schema } = state;
|
|
26
|
+
let found = false;
|
|
27
|
+
state.doc.nodesBetween(from, to, (node, _pos, parent) => {
|
|
28
|
+
if (found) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
const isTopLevelBlock = (parent === null || parent === void 0 ? void 0 : parent.type) === schema.topNodeType;
|
|
32
|
+
const listable = node.type === schema.nodes.paragraph ||
|
|
33
|
+
node.type === schema.nodes.list_item ||
|
|
34
|
+
isListNode(node, schema);
|
|
35
|
+
if (isTopLevelBlock && !listable) {
|
|
36
|
+
found = true;
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
return !isTopLevelBlock || isListNode(node, schema);
|
|
40
|
+
});
|
|
41
|
+
return found;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Classifies the selection for the list command ladder.
|
|
45
|
+
*
|
|
46
|
+
* @param state - the current editor state
|
|
47
|
+
* @param listType - the list type the command targets
|
|
48
|
+
* @returns the ladder branch to take, plus the innermost list depth when
|
|
49
|
+
* the selection sits inside a list
|
|
50
|
+
*/
|
|
51
|
+
export const resolveListContext = (state, listType) => {
|
|
52
|
+
const { $from, $to } = state.selection;
|
|
53
|
+
const fromDepth = innermostListDepth(state);
|
|
54
|
+
const sameTopLevelBlock = state.selection.empty ||
|
|
55
|
+
$from.sameParent($to) ||
|
|
56
|
+
$from.node(1) === $to.node(1);
|
|
57
|
+
if (fromDepth !== null && sameTopLevelBlock) {
|
|
58
|
+
return listContextAt($from, fromDepth, listType);
|
|
59
|
+
}
|
|
60
|
+
if (fromDepth === null && sameTopLevelBlock) {
|
|
61
|
+
return { kind: 'no-list', listDepth: null, singleBlock: true };
|
|
62
|
+
}
|
|
63
|
+
// The range spans multiple top-level blocks: uniform paragraphs mean a
|
|
64
|
+
// plain wrap; lists that are all of the target type mean a toggle;
|
|
65
|
+
// any other list in the mix means unification.
|
|
66
|
+
const listTypes = new Set();
|
|
67
|
+
let sawParagraph = false;
|
|
68
|
+
const startIndex = $from.index(0);
|
|
69
|
+
const endIndex = Math.min($to.index(0), state.doc.childCount - 1);
|
|
70
|
+
for (let i = startIndex; i <= endIndex; i++) {
|
|
71
|
+
const child = state.doc.child(i);
|
|
72
|
+
if (isListNode(child, state.schema)) {
|
|
73
|
+
listTypes.add(child.type);
|
|
74
|
+
}
|
|
75
|
+
else if (child.type === state.schema.nodes.paragraph) {
|
|
76
|
+
sawParagraph = true;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const uniformTargetLists = !sawParagraph && listTypes.size === 1 && listTypes.has(listType);
|
|
80
|
+
if (uniformTargetLists && fromDepth !== null) {
|
|
81
|
+
return listContextAt($from, fromDepth, listType);
|
|
82
|
+
}
|
|
83
|
+
if (listTypes.size > 0) {
|
|
84
|
+
return { kind: 'mixed', listDepth: null };
|
|
85
|
+
}
|
|
86
|
+
return { kind: 'no-list', listDepth: null, singleBlock: false };
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Converts the innermost list around the selection to the target list type.
|
|
90
|
+
* bullet_list and ordered_list share the list_item+ content model, so the
|
|
91
|
+
* node can change type in place.
|
|
92
|
+
*
|
|
93
|
+
* @param state - the current editor state
|
|
94
|
+
* @param listDepth - depth of the list node, from resolveListContext
|
|
95
|
+
* @param targetType - the list type to convert to
|
|
96
|
+
* @param dispatch - the dispatch function; omit for a dry-run capability check
|
|
97
|
+
* @returns true when the conversion applies
|
|
98
|
+
*/
|
|
99
|
+
export const convertInnermostList = (state, listDepth, targetType, dispatch) => {
|
|
100
|
+
const { $from } = state.selection;
|
|
101
|
+
const pos = $from.before(listDepth);
|
|
102
|
+
const node = state.doc.nodeAt(pos);
|
|
103
|
+
if (!node) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
if (dispatch) {
|
|
107
|
+
dispatch(state.tr
|
|
108
|
+
.setNodeMarkup(pos, targetType, listAttrsFor(targetType, node.attrs, state.schema))
|
|
109
|
+
.scrollIntoView());
|
|
110
|
+
}
|
|
111
|
+
return true;
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Turns a mixed top-level selection (paragraphs and lists) into a single
|
|
115
|
+
* list of the target type: paragraph runs are wrapped, lists are converted
|
|
116
|
+
* in place, and adjacent same-type lists are joined. Nesting inside
|
|
117
|
+
* converted lists is preserved.
|
|
118
|
+
*
|
|
119
|
+
* @param state - the current editor state
|
|
120
|
+
* @param targetType - the list type to unify into
|
|
121
|
+
* @param dispatch - the dispatch function; omit for a dry-run capability check
|
|
122
|
+
* @returns true when the unification applies
|
|
123
|
+
*/
|
|
124
|
+
export const unifyToList = (state, targetType, dispatch) => {
|
|
125
|
+
const { $from, $to } = state.selection;
|
|
126
|
+
if ($from.depth === 0 || $to.depth === 0) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
if (dispatch === undefined) {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
const tr = state.tr;
|
|
133
|
+
convertListsAndWrapRuns(tr, state, targetType, $from.index(0), $to.index(0));
|
|
134
|
+
joinAdjacentLists(tr, targetType, tr.mapping.map($from.before(1)), mapKeepBefore(tr, $to.after(1)));
|
|
135
|
+
dispatch(tr.scrollIntoView());
|
|
136
|
+
return true;
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Wraps a dispatch so that after a list is wrapped around the selection,
|
|
140
|
+
* adjacent top-level lists of the same type are joined with it.
|
|
141
|
+
*
|
|
142
|
+
* @param state - the editor state the wrap command runs on
|
|
143
|
+
* @param targetType - the list type being wrapped
|
|
144
|
+
* @param dispatch - the dispatch function; omitted for a dry-run capability check
|
|
145
|
+
* @returns the wrapped dispatch, or undefined when no dispatch was given
|
|
146
|
+
*/
|
|
147
|
+
export const joinAdjacentListsOnDispatch = (state, targetType, dispatch) => {
|
|
148
|
+
if (!dispatch) {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
const { $from, $to } = state.selection;
|
|
152
|
+
return (tr) => {
|
|
153
|
+
// The new list's outer boundaries: the start maps before the
|
|
154
|
+
// inserted wrapping, the end maps after it.
|
|
155
|
+
const start = mapKeepBefore(tr, $from.before(1));
|
|
156
|
+
const end = tr.mapping.map($to.after(1));
|
|
157
|
+
// Back to front, so the earlier boundary stays valid after a join.
|
|
158
|
+
joinSameTypeBoundary(tr, targetType, end);
|
|
159
|
+
joinSameTypeBoundary(tr, targetType, start);
|
|
160
|
+
dispatch(tr);
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
const joinSameTypeBoundary = (tr, targetType, boundary) => {
|
|
164
|
+
var _a, _b;
|
|
165
|
+
if (boundary <= 0 || boundary >= tr.doc.content.size) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const $boundary = tr.doc.resolve(boundary);
|
|
169
|
+
if (((_a = $boundary.nodeBefore) === null || _a === void 0 ? void 0 : _a.type) === targetType &&
|
|
170
|
+
((_b = $boundary.nodeAfter) === null || _b === void 0 ? void 0 : _b.type) === targetType) {
|
|
171
|
+
tr.join(boundary);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
const isListNode = (node, schema) => node.type === schema.nodes.bullet_list ||
|
|
175
|
+
node.type === schema.nodes.ordered_list;
|
|
176
|
+
const innermostListDepth = (state) => {
|
|
177
|
+
const { $from } = state.selection;
|
|
178
|
+
for (let depth = $from.depth; depth > 0; depth--) {
|
|
179
|
+
if (isListNode($from.node(depth), state.schema)) {
|
|
180
|
+
return depth;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return null;
|
|
184
|
+
};
|
|
185
|
+
const listContextAt = ($from, listDepth, listType) => ({
|
|
186
|
+
kind: $from.node(listDepth).type === listType ? 'same-type' : 'other-type',
|
|
187
|
+
listDepth: listDepth,
|
|
188
|
+
});
|
|
189
|
+
const listAttrsFor = (targetType, attrs, schema) => {
|
|
190
|
+
var _a;
|
|
191
|
+
if (targetType === schema.nodes.ordered_list) {
|
|
192
|
+
return Object.assign(Object.assign({}, attrs), { order: (_a = attrs.order) !== null && _a !== void 0 ? _a : 1 });
|
|
193
|
+
}
|
|
194
|
+
const { order } = attrs, withoutOrder = __rest(attrs, ["order"]);
|
|
195
|
+
return withoutOrder;
|
|
196
|
+
};
|
|
197
|
+
const mapKeepBefore = (tr, position) =>
|
|
198
|
+
// ProseMirror's Mapping.map takes (pos, assoc); the unicorn rule
|
|
199
|
+
// misreads it as Array#map with a `this` argument.
|
|
200
|
+
// eslint-disable-next-line unicorn/no-array-method-this-argument
|
|
201
|
+
tr.mapping.map(position, -1);
|
|
202
|
+
const wrapRunInList = (tr, targetType, runStart, runEnd) => {
|
|
203
|
+
const $start = tr.doc.resolve(tr.mapping.map(runStart) + 1);
|
|
204
|
+
const $end = tr.doc.resolve(mapKeepBefore(tr, runEnd) - 1);
|
|
205
|
+
const range = new NodeRange($start, $end, 0);
|
|
206
|
+
const wrapping = findWrapping(range, targetType);
|
|
207
|
+
if (!wrapping) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
tr.wrap(range, wrapping);
|
|
211
|
+
// tr.wrap puts the whole run inside a single list_item; splitting at
|
|
212
|
+
// each block boundary gives one item per block, the same shape
|
|
213
|
+
// wrapInList produces.
|
|
214
|
+
const listIndex = wrapping.findIndex((entry) => entry.type === targetType);
|
|
215
|
+
const splitDepth = wrapping.length - (listIndex + 1);
|
|
216
|
+
let splitPos = range.start + wrapping.length;
|
|
217
|
+
for (let i = range.startIndex; i < range.endIndex; i++) {
|
|
218
|
+
if (i > range.startIndex && canSplit(tr.doc, splitPos, splitDepth)) {
|
|
219
|
+
tr.split(splitPos, splitDepth);
|
|
220
|
+
splitPos += 2 * splitDepth;
|
|
221
|
+
}
|
|
222
|
+
splitPos += range.parent.child(i).nodeSize;
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
const convertListsAndWrapRuns = (tr, state, targetType, startIndex, endIndex) => {
|
|
226
|
+
// Positions computed against the pre-transform doc are mapped through
|
|
227
|
+
// tr.mapping when applied.
|
|
228
|
+
const doc = state.doc;
|
|
229
|
+
let runStart = null;
|
|
230
|
+
let runEnd = null;
|
|
231
|
+
let pos = 0;
|
|
232
|
+
for (let i = 0; i < doc.childCount; i++) {
|
|
233
|
+
const child = doc.child(i);
|
|
234
|
+
const inRange = i >= startIndex && i <= endIndex;
|
|
235
|
+
const isList = isListNode(child, state.schema);
|
|
236
|
+
if (inRange && child.type === state.schema.nodes.paragraph) {
|
|
237
|
+
runStart = runStart !== null && runStart !== void 0 ? runStart : pos;
|
|
238
|
+
runEnd = pos + child.nodeSize;
|
|
239
|
+
}
|
|
240
|
+
else if (runStart !== null && runEnd !== null) {
|
|
241
|
+
wrapRunInList(tr, targetType, runStart, runEnd);
|
|
242
|
+
runStart = null;
|
|
243
|
+
runEnd = null;
|
|
244
|
+
}
|
|
245
|
+
if (inRange && isList && child.type !== targetType) {
|
|
246
|
+
tr.setNodeMarkup(tr.mapping.map(pos), targetType, listAttrsFor(targetType, child.attrs, state.schema));
|
|
247
|
+
}
|
|
248
|
+
pos += child.nodeSize;
|
|
249
|
+
}
|
|
250
|
+
if (runStart !== null && runEnd !== null) {
|
|
251
|
+
wrapRunInList(tr, targetType, runStart, runEnd);
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
const joinAdjacentLists = (tr, targetType, mappedFrom, mappedTo) => {
|
|
255
|
+
// Scan the transformed doc's top-level boundaries back to front, so
|
|
256
|
+
// earlier join positions stay valid as joins shrink the doc.
|
|
257
|
+
const boundaries = [];
|
|
258
|
+
let boundary = 0;
|
|
259
|
+
for (let i = 0; i < tr.doc.childCount; i++) {
|
|
260
|
+
boundary += tr.doc.child(i).nodeSize;
|
|
261
|
+
boundaries.push(boundary);
|
|
262
|
+
}
|
|
263
|
+
for (let i = boundaries.length - 1; i >= 0; i--) {
|
|
264
|
+
const joinPos = boundaries[i];
|
|
265
|
+
if (joinPos <= mappedFrom || joinPos > mappedTo + 1) {
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
joinSameTypeBoundary(tr, targetType, joinPos);
|
|
269
|
+
}
|
|
270
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finds the depth of the nearest ancestor of a given node type.
|
|
3
|
+
*
|
|
4
|
+
* @param $pos - The resolved position in the document.
|
|
5
|
+
* @param type - The node type to search for.
|
|
6
|
+
* @returns The depth at which the node is found, or null if not found.
|
|
7
|
+
*/
|
|
8
|
+
export const findAncestorDepthOfType = ($pos, type) => {
|
|
9
|
+
for (let depth = $pos.depth; depth > 0; depth--) {
|
|
10
|
+
if ($pos.node(depth).type === type) {
|
|
11
|
+
return depth;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
};
|