@thomasfosterau/effect-richtext 0.0.0-stage → 0.1.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/LICENSE +48 -0
- package/README.md +118 -2
- package/dist/_virtual/_rolldown/runtime.js +12 -0
- package/dist/commands/commands.d.ts +323 -0
- package/dist/commands/commands.js +722 -0
- package/dist/commands/internal.js +43 -0
- package/dist/commands/keymaps.d.ts +46 -0
- package/dist/commands/keymaps.js +64 -0
- package/dist/commands.d.ts +3 -0
- package/dist/commands.js +3 -0
- package/dist/compat/commands.d.ts +250 -0
- package/dist/compat/commands.js +275 -0
- package/dist/compat/internal/core.d.ts +20 -0
- package/dist/compat/internal/core.js +148 -0
- package/dist/compat/internal/props.js +82 -0
- package/dist/compat/keymap.d.ts +21 -0
- package/dist/compat/keymap.js +38 -0
- package/dist/compat/model.d.ts +893 -0
- package/dist/compat/model.js +1212 -0
- package/dist/compat/orderedmap.d.ts +74 -0
- package/dist/compat/orderedmap.js +124 -0
- package/dist/compat/schema-basic.d.ts +38 -0
- package/dist/compat/schema-basic.js +238 -0
- package/dist/compat/schema-list.d.ts +81 -0
- package/dist/compat/schema-list.js +156 -0
- package/dist/compat/state.d.ts +415 -0
- package/dist/compat/state.js +689 -0
- package/dist/compat/test-builder.d.ts +98 -0
- package/dist/compat/test-builder.js +197 -0
- package/dist/compat/transform.d.ts +458 -0
- package/dist/compat/transform.js +803 -0
- package/dist/compat/view.d.ts +411 -0
- package/dist/compat/view.js +409 -0
- package/dist/dropcursor.d.ts +46 -0
- package/dist/dropcursor.js +176 -0
- package/dist/extensions/defaults.d.ts +716 -0
- package/dist/extensions/defaults.js +209 -0
- package/dist/extensions/editor.d.ts +246 -0
- package/dist/extensions/editor.js +271 -0
- package/dist/extensions/extension.d.ts +375 -0
- package/dist/extensions/extension.js +233 -0
- package/dist/extensions.d.ts +4 -0
- package/dist/extensions.js +4 -0
- package/dist/gapcursor.d.ts +66 -0
- package/dist/gapcursor.js +273 -0
- package/dist/history.d.ts +178 -0
- package/dist/history.js +412 -0
- package/dist/html.d.ts +158 -0
- package/dist/html.js +164 -0
- package/dist/inputrules.d.ts +271 -0
- package/dist/inputrules.js +321 -0
- package/dist/internal/attempt.js +15 -0
- package/dist/internal/json.js +29 -0
- package/dist/keymap/keymap.d.ts +130 -0
- package/dist/keymap/keymap.js +159 -0
- package/dist/keymap.d.ts +2 -0
- package/dist/keymap.js +1 -0
- package/dist/markdown/errors.d.ts +23 -0
- package/dist/markdown/errors.js +26 -0
- package/dist/markdown/from_markdown.d.ts +185 -0
- package/dist/markdown/from_markdown.js +266 -0
- package/dist/markdown/schema.d.ts +522 -0
- package/dist/markdown/schema.js +292 -0
- package/dist/markdown/to_markdown.d.ts +251 -0
- package/dist/markdown/to_markdown.js +413 -0
- package/dist/markdown.d.ts +5 -0
- package/dist/markdown.js +5 -0
- package/dist/model/attrsCodec.js +48 -0
- package/dist/model/comparedeep.js +17 -0
- package/dist/model/content.d.ts +232 -0
- package/dist/model/content.js +630 -0
- package/dist/model/diff.js +66 -0
- package/dist/model/dom.d.ts +3 -0
- package/dist/model/errors.d.ts +90 -0
- package/dist/model/errors.js +76 -0
- package/dist/model/fragment.d.ts +131 -0
- package/dist/model/fragment.js +262 -0
- package/dist/model/from_dom.d.ts +299 -0
- package/dist/model/from_dom.js +618 -0
- package/dist/model/json.d.ts +37 -0
- package/dist/model/json.js +126 -0
- package/dist/model/mark.d.ts +73 -0
- package/dist/model/mark.js +121 -0
- package/dist/model/node.d.ts +267 -0
- package/dist/model/node.js +434 -0
- package/dist/model/replace.d.ts +78 -0
- package/dist/model/replace.js +207 -0
- package/dist/model/resolvedpos.d.ts +196 -0
- package/dist/model/resolvedpos.js +305 -0
- package/dist/model/schema.d.ts +740 -0
- package/dist/model/schema.js +451 -0
- package/dist/model/to_dom.d.ts +169 -0
- package/dist/model/to_dom.js +238 -0
- package/dist/model.d.ts +12 -0
- package/dist/model.js +12 -0
- package/dist/placeholder.d.ts +53 -0
- package/dist/placeholder.js +79 -0
- package/dist/reactive/observer.d.ts +54 -0
- package/dist/reactive/observer.js +61 -0
- package/dist/reactive/selectors.d.ts +22 -0
- package/dist/reactive/selectors.js +61 -0
- package/dist/reactive/stateref.d.ts +72 -0
- package/dist/reactive/stateref.js +71 -0
- package/dist/reactive/streams.d.ts +83 -0
- package/dist/reactive/streams.js +85 -0
- package/dist/reactive.d.ts +16 -0
- package/dist/reactive.js +26 -0
- package/dist/schema-basic.d.ts +448 -0
- package/dist/schema-basic.js +269 -0
- package/dist/schema-list/commands.d.ts +66 -0
- package/dist/schema-list/commands.js +203 -0
- package/dist/schema-list.d.ts +92 -0
- package/dist/schema-list.js +100 -0
- package/dist/state/errors.d.ts +39 -0
- package/dist/state/errors.js +32 -0
- package/dist/state/plugin.d.ts +232 -0
- package/dist/state/plugin.js +82 -0
- package/dist/state/selection.d.ts +297 -0
- package/dist/state/selection.js +486 -0
- package/dist/state/state.d.ts +212 -0
- package/dist/state/state.js +489 -0
- package/dist/state/transaction.d.ts +145 -0
- package/dist/state/transaction.js +195 -0
- package/dist/state.d.ts +6 -0
- package/dist/state.js +6 -0
- package/dist/test-builder.d.ts +3582 -0
- package/dist/test-builder.js +239 -0
- package/dist/transform/attr_step.d.ts +60 -0
- package/dist/transform/attr_step.js +105 -0
- package/dist/transform/errors.d.ts +50 -0
- package/dist/transform/errors.js +35 -0
- package/dist/transform/map.d.ts +182 -0
- package/dist/transform/map.js +280 -0
- package/dist/transform/mark.js +98 -0
- package/dist/transform/mark_set_step.js +69 -0
- package/dist/transform/mark_step.d.ts +113 -0
- package/dist/transform/mark_step.js +225 -0
- package/dist/transform/replace.d.ts +18 -0
- package/dist/transform/replace.js +381 -0
- package/dist/transform/replace_step.d.ts +109 -0
- package/dist/transform/replace_step.js +175 -0
- package/dist/transform/step.d.ts +157 -0
- package/dist/transform/step.js +168 -0
- package/dist/transform/structure.d.ts +89 -0
- package/dist/transform/structure.js +350 -0
- package/dist/transform/transform.d.ts +248 -0
- package/dist/transform/transform.js +373 -0
- package/dist/transform.d.ts +10 -0
- package/dist/transform.js +10 -0
- package/dist/view/browser.js +39 -0
- package/dist/view/capturekeys.js +282 -0
- package/dist/view/clipboard.d.ts +8 -0
- package/dist/view/clipboard.js +245 -0
- package/dist/view/decoration.d.ts +339 -0
- package/dist/view/decoration.js +566 -0
- package/dist/view/dom.d.ts +18 -0
- package/dist/view/dom.js +140 -0
- package/dist/view/domchange.js +295 -0
- package/dist/view/domcoords.d.ts +22 -0
- package/dist/view/domcoords.js +448 -0
- package/dist/view/domobserver.d.ts +47 -0
- package/dist/view/domobserver.js +328 -0
- package/dist/view/errors.d.ts +18 -0
- package/dist/view/errors.js +21 -0
- package/dist/view/input.d.ts +58 -0
- package/dist/view/input.js +704 -0
- package/dist/view/selection.js +198 -0
- package/dist/view/view.d.ts +699 -0
- package/dist/view/view.js +623 -0
- package/dist/view/viewdesc.d.ts +236 -0
- package/dist/view/viewdesc.js +1205 -0
- package/dist/view-css.d.ts +43 -0
- package/dist/view-css.js +124 -0
- package/dist/view.d.ts +6 -0
- package/dist/view.js +4 -0
- package/package.json +206 -3
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { NodeRange } from "../model/resolvedpos.js";
|
|
2
|
+
import { AnySchema, NodeAttrsInput, NodeNames, NodeType } from "../model/schema.js";
|
|
3
|
+
import "../model.js";
|
|
4
|
+
import { Command, Transaction } from "../state/transaction.js";
|
|
5
|
+
import "../state.js";
|
|
6
|
+
/**
|
|
7
|
+
* Returns a command function that wraps the selection in a list with
|
|
8
|
+
* the given type and attributes. If `dispatch` is not given, only
|
|
9
|
+
* succeeds with a value indicating whether this is possible, without
|
|
10
|
+
* performing the change.
|
|
11
|
+
*
|
|
12
|
+
* @since 0.1.0
|
|
13
|
+
* @category commands
|
|
14
|
+
*/
|
|
15
|
+
export declare const wrapInList: <Sc extends AnySchema, N extends NodeNames<Sc>>(listType: NodeType<Sc, N>, attrs?: NodeAttrsInput<Sc, N> | null) => Command<Sc>;
|
|
16
|
+
/**
|
|
17
|
+
* Try to wrap the given node range in a list of the given type. Return
|
|
18
|
+
* `true` when this is possible, `false` otherwise. When `tr` is
|
|
19
|
+
* non-null, the wrapping is added to that transaction. When it is
|
|
20
|
+
* `null`, the function only queries whether the wrapping is possible.
|
|
21
|
+
*
|
|
22
|
+
* @since 0.1.0
|
|
23
|
+
* @category transforms
|
|
24
|
+
*/
|
|
25
|
+
export declare function wrapRangeInList<Sc extends AnySchema, N extends NodeNames<Sc>>(tr: Transaction<Sc> | null, range: NodeRange<Sc>, listType: NodeType<Sc, N>, attrs?: NodeAttrsInput<Sc, N> | null): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* The list item type(s) a list command acts on: one node type, or
|
|
28
|
+
* several for lists that mix kinds of items (prosemirror-schema-list
|
|
29
|
+
* 1.6.0).
|
|
30
|
+
*
|
|
31
|
+
* @since 0.1.0
|
|
32
|
+
* @category models
|
|
33
|
+
*/
|
|
34
|
+
export type ItemTypes<Sc extends AnySchema, N extends NodeNames<Sc>> = NodeType<Sc, N> | ReadonlyArray<NodeType<Sc, N>>;
|
|
35
|
+
/**
|
|
36
|
+
* Build a command that splits a non-empty textblock at the top level of
|
|
37
|
+
* a list item by also splitting that list item.
|
|
38
|
+
*
|
|
39
|
+
* @since 0.1.0
|
|
40
|
+
* @category commands
|
|
41
|
+
*/
|
|
42
|
+
export declare const splitListItem: <Sc extends AnySchema, N extends NodeNames<Sc>>(itemType: ItemTypes<Sc, N>, itemAttrs?: NodeAttrsInput<Sc, N>) => Command<Sc>;
|
|
43
|
+
/**
|
|
44
|
+
* Acts like `splitListItem`, but without resetting the set of active
|
|
45
|
+
* marks at the cursor.
|
|
46
|
+
*
|
|
47
|
+
* @since 0.1.0
|
|
48
|
+
* @category commands
|
|
49
|
+
*/
|
|
50
|
+
export declare const splitListItemKeepMarks: <Sc extends AnySchema, N extends NodeNames<Sc>>(itemType: ItemTypes<Sc, N>, itemAttrs?: NodeAttrsInput<Sc, N>) => Command<Sc>;
|
|
51
|
+
/**
|
|
52
|
+
* Create a command to lift the list item around the selection up into
|
|
53
|
+
* a wrapping list.
|
|
54
|
+
*
|
|
55
|
+
* @since 0.1.0
|
|
56
|
+
* @category commands
|
|
57
|
+
*/
|
|
58
|
+
export declare const liftListItem: <Sc extends AnySchema, N extends NodeNames<Sc>>(itemType: ItemTypes<Sc, N>) => Command<Sc>;
|
|
59
|
+
/**
|
|
60
|
+
* Create a command to sink the list item around the selection down into
|
|
61
|
+
* an inner list.
|
|
62
|
+
*
|
|
63
|
+
* @since 0.1.0
|
|
64
|
+
* @category commands
|
|
65
|
+
*/
|
|
66
|
+
export declare const sinkListItem: <Sc extends AnySchema, N extends NodeNames<Sc>>(itemType: ItemTypes<Sc, N>) => Command<Sc>;
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { done, keepMarks, syncCommand } from "../commands/internal.js";
|
|
2
|
+
import { Fragment } from "../model/fragment.js";
|
|
3
|
+
import { NodeRange } from "../model/resolvedpos.js";
|
|
4
|
+
import { Slice } from "../model/replace.js";
|
|
5
|
+
import { Selection } from "../state/selection.js";
|
|
6
|
+
import { canJoin, canSplit, findWrappingOrNull, liftTargetOrNull } from "../transform/structure.js";
|
|
7
|
+
import { ReplaceAroundStep } from "../transform/replace_step.js";
|
|
8
|
+
// src/schema-list/commands.ts
|
|
9
|
+
/**
|
|
10
|
+
* List commands, ported from `prosemirror-schema-list`.
|
|
11
|
+
*
|
|
12
|
+
* Ported from prosemirror-schema-list (MIT, Marijn Haverbeke and others).
|
|
13
|
+
*
|
|
14
|
+
* @since 0.1.0
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Returns a command function that wraps the selection in a list with
|
|
18
|
+
* the given type and attributes. If `dispatch` is not given, only
|
|
19
|
+
* succeeds with a value indicating whether this is possible, without
|
|
20
|
+
* performing the change.
|
|
21
|
+
*
|
|
22
|
+
* @since 0.1.0
|
|
23
|
+
* @category commands
|
|
24
|
+
*/
|
|
25
|
+
const wrapInList = (listType, attrs = null) => syncCommand((state, dispatching) => {
|
|
26
|
+
const { $from, $to } = state.selection;
|
|
27
|
+
const range = $from.blockRangeOrNull($to);
|
|
28
|
+
if (!range) return false;
|
|
29
|
+
const tr = dispatching ? state.tr : null;
|
|
30
|
+
if (!wrapRangeInList(tr, range, listType, attrs)) return false;
|
|
31
|
+
return tr ? tr.scrollIntoView() : true;
|
|
32
|
+
});
|
|
33
|
+
/**
|
|
34
|
+
* Try to wrap the given node range in a list of the given type. Return
|
|
35
|
+
* `true` when this is possible, `false` otherwise. When `tr` is
|
|
36
|
+
* non-null, the wrapping is added to that transaction. When it is
|
|
37
|
+
* `null`, the function only queries whether the wrapping is possible.
|
|
38
|
+
*
|
|
39
|
+
* @since 0.1.0
|
|
40
|
+
* @category transforms
|
|
41
|
+
*/
|
|
42
|
+
function wrapRangeInList(tr, range, listType, attrs = null) {
|
|
43
|
+
let doJoin = false, outerRange = range;
|
|
44
|
+
const doc = range.$from.doc;
|
|
45
|
+
if (range.depth >= 2 && range.$from.node(range.depth - 1).type.compatibleContent(listType) && range.startIndex === 0) {
|
|
46
|
+
if (range.$from.index(range.depth - 1) === 0) return false;
|
|
47
|
+
const $insert = doc.resolveUnsafe(range.start - 2);
|
|
48
|
+
outerRange = new NodeRange($insert, $insert, range.depth);
|
|
49
|
+
if (range.endIndex < range.parent.childCount) range = new NodeRange(range.$from, doc.resolveUnsafe(range.$to.end(range.depth)), range.depth);
|
|
50
|
+
doJoin = true;
|
|
51
|
+
}
|
|
52
|
+
const wrap = findWrappingOrNull(outerRange, listType, attrs, range);
|
|
53
|
+
if (!wrap) return false;
|
|
54
|
+
if (tr) doWrapInList(tr, range, wrap, doJoin, listType);
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
function doWrapInList(tr, range, wrappers, joinBefore, listType) {
|
|
58
|
+
let content = Fragment.empty;
|
|
59
|
+
for (let i = wrappers.length - 1; i >= 0; i--) content = Fragment.from(wrappers[i].type.createUnsafe(wrappers[i].attrs, content));
|
|
60
|
+
tr.stepUnsafe(new ReplaceAroundStep(range.start - (joinBefore ? 2 : 0), range.end, range.start, range.end, new Slice(content, 0, 0), wrappers.length, true));
|
|
61
|
+
let found = 0;
|
|
62
|
+
for (let i = 0; i < wrappers.length; i++) if (wrappers[i].type === listType) found = i + 1;
|
|
63
|
+
const splitDepth = wrappers.length - found;
|
|
64
|
+
let splitPos = range.start + wrappers.length - (joinBefore ? 2 : 0);
|
|
65
|
+
const parent = range.parent;
|
|
66
|
+
for (let i = range.startIndex, e = range.endIndex, first = true; i < e; i++, first = false) {
|
|
67
|
+
if (!first && splitDepth && canSplit(tr.doc, splitPos, splitDepth)) {
|
|
68
|
+
tr.splitUnsafe(splitPos, splitDepth);
|
|
69
|
+
splitPos += 2 * splitDepth;
|
|
70
|
+
}
|
|
71
|
+
splitPos += parent.childUnsafe(i).nodeSize;
|
|
72
|
+
}
|
|
73
|
+
return tr;
|
|
74
|
+
}
|
|
75
|
+
const isItem = (itemType, type) => Array.isArray(itemType) ? itemType.indexOf(type) > -1 : type === itemType;
|
|
76
|
+
const itemRange = (state, itemType) => {
|
|
77
|
+
const { $from, $to } = state.selection;
|
|
78
|
+
return $from.blockRangeOrNull($to, (node) => {
|
|
79
|
+
const first = node.content.content[0];
|
|
80
|
+
return !!first && isItem(itemType, first.type);
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Build a command that splits a non-empty textblock at the top level of
|
|
85
|
+
* a list item by also splitting that list item.
|
|
86
|
+
*
|
|
87
|
+
* @since 0.1.0
|
|
88
|
+
* @category commands
|
|
89
|
+
*/
|
|
90
|
+
const splitListItem = (itemType, itemAttrs) => syncCommand((state, dispatching) => {
|
|
91
|
+
const sel = state.selection, { $from, $to } = sel;
|
|
92
|
+
const node = sel.node;
|
|
93
|
+
if (node && node.isBlock || $from.depth < 2 || !$from.sameParent($to)) return false;
|
|
94
|
+
const grandParent = $from.node(-1);
|
|
95
|
+
if (!isItem(itemType, grandParent.type)) return false;
|
|
96
|
+
if ($from.parent.content.size === 0 && $from.node(-1).childCount === $from.indexAfter(-1)) {
|
|
97
|
+
if ($from.depth === 3 || !isItem(itemType, $from.node(-3).type) || $from.index(-2) !== $from.node(-2).childCount - 1) return false;
|
|
98
|
+
return done(dispatching, () => {
|
|
99
|
+
let wrap = Fragment.empty;
|
|
100
|
+
const depthBefore = $from.index(-1) ? 1 : $from.index(-2) ? 2 : 3;
|
|
101
|
+
for (let d = $from.depth - depthBefore; d >= $from.depth - 3; d--) wrap = Fragment.from($from.node(d).copy(wrap));
|
|
102
|
+
const depthAfter = $from.indexAfter(-1) < $from.node(-2).childCount ? 1 : $from.indexAfter(-2) < $from.node(-3).childCount ? 2 : 3;
|
|
103
|
+
wrap = wrap.append(Fragment.from($from.node(-3).type.createAndFillOrNull()));
|
|
104
|
+
const start = $from.beforeUnsafe($from.depth - (depthBefore - 1));
|
|
105
|
+
const tr = state.tr.replaceUnsafe(start, $from.afterUnsafe(-depthAfter), new Slice(wrap, 4 - depthBefore, 0));
|
|
106
|
+
let sel = -1;
|
|
107
|
+
tr.doc.nodesBetween(start, tr.doc.content.size, (node, pos) => {
|
|
108
|
+
if (sel > -1) return false;
|
|
109
|
+
if (node.isTextblock && node.content.size === 0) sel = pos + 1;
|
|
110
|
+
});
|
|
111
|
+
if (sel > -1) tr.setSelectionUnsafe(Selection.near(tr.doc.resolveUnsafe(sel)));
|
|
112
|
+
return tr.scrollIntoView();
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
const nextType = $to.pos === $from.end() ? grandParent.contentMatchAtUnsafe(0).defaultTypeOrNull : null;
|
|
116
|
+
const tr = state.tr.deleteUnsafe($from.pos, $to.pos);
|
|
117
|
+
const types = nextType ? [itemAttrs ? {
|
|
118
|
+
type: grandParent.type,
|
|
119
|
+
attrs: itemAttrs
|
|
120
|
+
} : null, { type: nextType }] : void 0;
|
|
121
|
+
if (!canSplit(tr.doc, $from.pos, 2, types)) return false;
|
|
122
|
+
return done(dispatching, () => tr.splitUnsafe($from.pos, 2, types).scrollIntoView());
|
|
123
|
+
});
|
|
124
|
+
/**
|
|
125
|
+
* Acts like `splitListItem`, but without resetting the set of active
|
|
126
|
+
* marks at the cursor.
|
|
127
|
+
*
|
|
128
|
+
* @since 0.1.0
|
|
129
|
+
* @category commands
|
|
130
|
+
*/
|
|
131
|
+
const splitListItemKeepMarks = (itemType, itemAttrs) => {
|
|
132
|
+
const split = splitListItem(itemType, itemAttrs);
|
|
133
|
+
return (state, dispatch) => split(state, keepMarks(state, dispatch));
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Create a command to lift the list item around the selection up into
|
|
137
|
+
* a wrapping list.
|
|
138
|
+
*
|
|
139
|
+
* @since 0.1.0
|
|
140
|
+
* @category commands
|
|
141
|
+
*/
|
|
142
|
+
const liftListItem = (itemType) => syncCommand((state, dispatching) => {
|
|
143
|
+
const { $from } = state.selection;
|
|
144
|
+
const range = itemRange(state, itemType);
|
|
145
|
+
if (!range) return false;
|
|
146
|
+
if (!dispatching) return true;
|
|
147
|
+
if (isItem(itemType, $from.node(range.depth - 1).type)) return liftToOuterList(state, range);
|
|
148
|
+
else return liftOutOfList(state, range);
|
|
149
|
+
});
|
|
150
|
+
function liftToOuterList(state, range) {
|
|
151
|
+
const tr = state.tr, end = range.end, endOfList = range.$to.end(range.depth);
|
|
152
|
+
const itemType = range.parent.childUnsafe(range.endIndex - 1).type;
|
|
153
|
+
if (end < endOfList) {
|
|
154
|
+
tr.stepUnsafe(new ReplaceAroundStep(end - 1, endOfList, end, endOfList, new Slice(Fragment.from(itemType.createUnsafe(null, range.parent.copy())), 1, 0), 1, true));
|
|
155
|
+
range = new NodeRange(tr.doc.resolveUnsafe(range.$from.pos), tr.doc.resolveUnsafe(endOfList), range.depth);
|
|
156
|
+
}
|
|
157
|
+
const target = liftTargetOrNull(range);
|
|
158
|
+
if (target == null) return false;
|
|
159
|
+
tr.liftUnsafe(range, target);
|
|
160
|
+
const $after = tr.doc.resolveUnsafe(tr.mapping.map(end, -1) - 1);
|
|
161
|
+
if (canJoin(tr.doc, $after.pos) && $after.nodeBeforeOrNull.type === $after.nodeAfterOrNull.type) tr.joinUnsafe($after.pos);
|
|
162
|
+
return tr.scrollIntoView();
|
|
163
|
+
}
|
|
164
|
+
function liftOutOfList(state, range) {
|
|
165
|
+
const tr = state.tr, list = range.parent;
|
|
166
|
+
for (let pos = range.end, i = range.endIndex - 1, e = range.startIndex; i > e; i--) {
|
|
167
|
+
pos -= list.childUnsafe(i).nodeSize;
|
|
168
|
+
tr.deleteUnsafe(pos - 1, pos + 1);
|
|
169
|
+
}
|
|
170
|
+
const $start = tr.doc.resolveUnsafe(range.start), item = $start.nodeAfterOrNull;
|
|
171
|
+
if (tr.mapping.map(range.end) !== range.start + item.nodeSize) return false;
|
|
172
|
+
const atStart = range.startIndex === 0, atEnd = range.endIndex === list.childCount;
|
|
173
|
+
const parent = $start.node(-1), indexBefore = $start.index(-1);
|
|
174
|
+
if (!parent.canReplace(indexBefore + (atStart ? 0 : 1), indexBefore + 1, item.content.append(atEnd ? Fragment.empty : Fragment.from(list)))) return false;
|
|
175
|
+
const start = $start.pos, end = start + item.nodeSize;
|
|
176
|
+
tr.stepUnsafe(new ReplaceAroundStep(start - (atStart ? 1 : 0), end + (atEnd ? 1 : 0), start + 1, end - 1, new Slice((atStart ? Fragment.empty : Fragment.from(list.copy(Fragment.empty))).append(atEnd ? Fragment.empty : Fragment.from(list.copy(Fragment.empty))), atStart ? 0 : 1, atEnd ? 0 : 1), atStart ? 0 : 1));
|
|
177
|
+
return tr.scrollIntoView();
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Create a command to sink the list item around the selection down into
|
|
181
|
+
* an inner list.
|
|
182
|
+
*
|
|
183
|
+
* @since 0.1.0
|
|
184
|
+
* @category commands
|
|
185
|
+
*/
|
|
186
|
+
const sinkListItem = (itemType) => syncCommand((state, dispatching) => {
|
|
187
|
+
const range = itemRange(state, itemType);
|
|
188
|
+
if (!range) return false;
|
|
189
|
+
const startIndex = range.startIndex;
|
|
190
|
+
if (startIndex === 0) return false;
|
|
191
|
+
const parent = range.parent, nodeBefore = parent.childUnsafe(startIndex - 1);
|
|
192
|
+
if (!isItem(itemType, nodeBefore.type)) return false;
|
|
193
|
+
return done(dispatching, () => {
|
|
194
|
+
const lastBefore = nodeBefore.content.content[nodeBefore.childCount - 1];
|
|
195
|
+
const nestedBefore = !!lastBefore && lastBefore.type === parent.type;
|
|
196
|
+
const nestedItem = nestedBefore ? lastBefore.content.content[lastBefore.childCount - 1] : void 0;
|
|
197
|
+
const inner = Fragment.from(nestedItem ? nestedItem.type.createUnsafe() : null);
|
|
198
|
+
const slice = new Slice(Fragment.from(nodeBefore.type.createUnsafe(null, Fragment.from(parent.type.createUnsafe(null, inner)))), nestedBefore ? 3 : 1, 0);
|
|
199
|
+
const before = range.start, after = range.end;
|
|
200
|
+
return state.tr.stepUnsafe(new ReplaceAroundStep(before - (nestedBefore ? 3 : 1), after, before, after, slice, 1, true)).scrollIntoView();
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
export { liftListItem, sinkListItem, splitListItem, splitListItemKeepMarks, wrapInList, wrapRangeInList };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { NodeSpec } from "./model/schema.js";
|
|
2
|
+
import { Node } from "./model/node.js";
|
|
3
|
+
import { ContentExpr, ContentInput } from "./model/content.js";
|
|
4
|
+
import "./model.js";
|
|
5
|
+
import { ItemTypes, liftListItem, sinkListItem, splitListItem, splitListItemKeepMarks, wrapInList, wrapRangeInList } from "./schema-list/commands.js";
|
|
6
|
+
import * as S from "effect/Schema";
|
|
7
|
+
/**
|
|
8
|
+
* An ordered list node spec. Has a single attribute, `order`, which
|
|
9
|
+
* determines the number at which the list starts counting, and
|
|
10
|
+
* defaults to 1. Represented as an `<ol>` element.
|
|
11
|
+
*
|
|
12
|
+
* @since 0.1.0
|
|
13
|
+
* @category specs
|
|
14
|
+
*/
|
|
15
|
+
export declare const orderedList: {
|
|
16
|
+
readonly attrs: {
|
|
17
|
+
readonly order: {
|
|
18
|
+
readonly schema: S.Number;
|
|
19
|
+
readonly default: 1;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
readonly parseDOM: readonly [{
|
|
23
|
+
readonly tag: "ol";
|
|
24
|
+
readonly getAttrs: (dom: HTMLElement) => {
|
|
25
|
+
order: number;
|
|
26
|
+
};
|
|
27
|
+
}];
|
|
28
|
+
readonly toDOM: (node: Node<any, any>) => readonly any[];
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* A bullet list node spec, represented in the DOM as `<ul>`.
|
|
32
|
+
*
|
|
33
|
+
* @since 0.1.0
|
|
34
|
+
* @category specs
|
|
35
|
+
*/
|
|
36
|
+
export declare const bulletList: {
|
|
37
|
+
readonly parseDOM: readonly [{
|
|
38
|
+
readonly tag: "ul";
|
|
39
|
+
}];
|
|
40
|
+
readonly toDOM: () => readonly any[] | readonly [string, ...any[]];
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* A list item (`<li>`) spec.
|
|
44
|
+
*
|
|
45
|
+
* @since 0.1.0
|
|
46
|
+
* @category specs
|
|
47
|
+
*/
|
|
48
|
+
export declare const listItem: {
|
|
49
|
+
readonly parseDOM: readonly [{
|
|
50
|
+
readonly tag: "li";
|
|
51
|
+
}];
|
|
52
|
+
readonly toDOM: () => readonly any[] | readonly [string, ...any[]];
|
|
53
|
+
readonly defining: true;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* The node specs added by `addListNodes`.
|
|
57
|
+
*
|
|
58
|
+
* @since 0.1.0
|
|
59
|
+
* @category type-level
|
|
60
|
+
*/
|
|
61
|
+
export type ListNodes<ItemRefs extends string, Group extends string | undefined> = {
|
|
62
|
+
readonly ordered_list: typeof orderedList & {
|
|
63
|
+
readonly content: ContentExpr<"list_item">;
|
|
64
|
+
readonly group: Group;
|
|
65
|
+
};
|
|
66
|
+
readonly bullet_list: typeof bulletList & {
|
|
67
|
+
readonly content: ContentExpr<"list_item">;
|
|
68
|
+
readonly group: Group;
|
|
69
|
+
};
|
|
70
|
+
readonly list_item: typeof listItem & {
|
|
71
|
+
readonly content: ContentExpr<ItemRefs>;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Convenience function for adding list-related node types to a set of
|
|
76
|
+
* node specs. Adds them under the names `"ordered_list"`,
|
|
77
|
+
* `"bullet_list"`, and `"list_item"`.
|
|
78
|
+
*
|
|
79
|
+
* `itemContent` determines the content expression for the list items.
|
|
80
|
+
* If you want the commands defined in this module to apply to your
|
|
81
|
+
* list structure, it should have a shape like
|
|
82
|
+
* `Content.seq("paragraph", Content.zeroOrMore("block"))`.
|
|
83
|
+
* `listGroup` can be given to assign a group name to the list node
|
|
84
|
+
* types, for example `"block"`.
|
|
85
|
+
*
|
|
86
|
+
* @since 0.1.0
|
|
87
|
+
* @category specs
|
|
88
|
+
*/
|
|
89
|
+
export declare const addListNodes: <const N extends {
|
|
90
|
+
readonly [name: string]: NodeSpec;
|
|
91
|
+
}, const ItemRefs extends string, const Group extends string | undefined = undefined>(nodes: N, itemContent: ContentInput<ItemRefs>, listGroup?: Group) => N & ListNodes<ItemRefs, Group>;
|
|
92
|
+
export { ItemTypes, liftListItem, sinkListItem, splitListItem, splitListItemKeepMarks, wrapInList, wrapRangeInList };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { oneOrMore, ref } from "./model/content.js";
|
|
2
|
+
import { nodeSpec } from "./model/schema.js";
|
|
3
|
+
import { liftListItem, sinkListItem, splitListItem, splitListItemKeepMarks, wrapInList, wrapRangeInList } from "./schema-list/commands.js";
|
|
4
|
+
import * as Predicate from "effect/Predicate";
|
|
5
|
+
import * as S from "effect/Schema";
|
|
6
|
+
// src/schema-list.ts
|
|
7
|
+
/**
|
|
8
|
+
* List node specs and list commands, ported from
|
|
9
|
+
* `prosemirror-schema-list`.
|
|
10
|
+
*
|
|
11
|
+
* @since 0.1.0
|
|
12
|
+
*/
|
|
13
|
+
const olDOM = ["ol", 0];
|
|
14
|
+
const ulDOM = ["ul", 0];
|
|
15
|
+
const liDOM = ["li", 0];
|
|
16
|
+
/**
|
|
17
|
+
* An ordered list node spec. Has a single attribute, `order`, which
|
|
18
|
+
* determines the number at which the list starts counting, and
|
|
19
|
+
* defaults to 1. Represented as an `<ol>` element.
|
|
20
|
+
*
|
|
21
|
+
* @since 0.1.0
|
|
22
|
+
* @category specs
|
|
23
|
+
*/
|
|
24
|
+
const orderedList = nodeSpec({
|
|
25
|
+
attrs: { order: {
|
|
26
|
+
schema: S.Number,
|
|
27
|
+
default: 1
|
|
28
|
+
} },
|
|
29
|
+
parseDOM: [{
|
|
30
|
+
tag: "ol",
|
|
31
|
+
getAttrs(dom) {
|
|
32
|
+
return { order: dom.hasAttribute("start") ? +dom.getAttribute("start") : 1 };
|
|
33
|
+
}
|
|
34
|
+
}],
|
|
35
|
+
toDOM(node) {
|
|
36
|
+
return node.attrs.order === 1 ? olDOM : [
|
|
37
|
+
"ol",
|
|
38
|
+
{ start: node.attrs.order },
|
|
39
|
+
0
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
/**
|
|
44
|
+
* A bullet list node spec, represented in the DOM as `<ul>`.
|
|
45
|
+
*
|
|
46
|
+
* @since 0.1.0
|
|
47
|
+
* @category specs
|
|
48
|
+
*/
|
|
49
|
+
const bulletList = nodeSpec({
|
|
50
|
+
parseDOM: [{ tag: "ul" }],
|
|
51
|
+
toDOM() {
|
|
52
|
+
return ulDOM;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
/**
|
|
56
|
+
* A list item (`<li>`) spec.
|
|
57
|
+
*
|
|
58
|
+
* @since 0.1.0
|
|
59
|
+
* @category specs
|
|
60
|
+
*/
|
|
61
|
+
const listItem = nodeSpec({
|
|
62
|
+
parseDOM: [{ tag: "li" }],
|
|
63
|
+
toDOM() {
|
|
64
|
+
return liDOM;
|
|
65
|
+
},
|
|
66
|
+
defining: true
|
|
67
|
+
});
|
|
68
|
+
/**
|
|
69
|
+
* Convenience function for adding list-related node types to a set of
|
|
70
|
+
* node specs. Adds them under the names `"ordered_list"`,
|
|
71
|
+
* `"bullet_list"`, and `"list_item"`.
|
|
72
|
+
*
|
|
73
|
+
* `itemContent` determines the content expression for the list items.
|
|
74
|
+
* If you want the commands defined in this module to apply to your
|
|
75
|
+
* list structure, it should have a shape like
|
|
76
|
+
* `Content.seq("paragraph", Content.zeroOrMore("block"))`.
|
|
77
|
+
* `listGroup` can be given to assign a group name to the list node
|
|
78
|
+
* types, for example `"block"`.
|
|
79
|
+
*
|
|
80
|
+
* @since 0.1.0
|
|
81
|
+
* @category specs
|
|
82
|
+
*/
|
|
83
|
+
const addListNodes = (nodes, itemContent, listGroup) => ({
|
|
84
|
+
...nodes,
|
|
85
|
+
ordered_list: {
|
|
86
|
+
...orderedList,
|
|
87
|
+
content: oneOrMore("list_item"),
|
|
88
|
+
group: listGroup
|
|
89
|
+
},
|
|
90
|
+
bullet_list: {
|
|
91
|
+
...bulletList,
|
|
92
|
+
content: oneOrMore("list_item"),
|
|
93
|
+
group: listGroup
|
|
94
|
+
},
|
|
95
|
+
list_item: {
|
|
96
|
+
...listItem,
|
|
97
|
+
content: Predicate.isString(itemContent) ? ref(itemContent) : itemContent
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
export { addListNodes, bulletList, liftListItem, listItem, orderedList, sinkListItem, splitListItem, splitListItemKeepMarks, wrapInList, wrapRangeInList };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
declare const StateError_base: Schema.Class<StateError, Schema.TaggedStruct<"StateError", {
|
|
3
|
+
readonly message: Schema.String;
|
|
4
|
+
}>, import("effect/Cause").YieldableError>;
|
|
5
|
+
/**
|
|
6
|
+
* An invalid editor state operation: a state configuration without a
|
|
7
|
+
* schema or document, two different instances of a keyed plugin, a
|
|
8
|
+
* transaction applied to a state it wasn't created for, or invalid
|
|
9
|
+
* JSON field names.
|
|
10
|
+
*
|
|
11
|
+
* @since 0.1.0
|
|
12
|
+
* @category errors
|
|
13
|
+
*/
|
|
14
|
+
export declare class StateError extends StateError_base {}
|
|
15
|
+
declare const SelectionError_base: Schema.Class<SelectionError, Schema.TaggedStruct<"SelectionError", {
|
|
16
|
+
readonly message: Schema.String;
|
|
17
|
+
}>, import("effect/Cause").YieldableError>;
|
|
18
|
+
/**
|
|
19
|
+
* An invalid selection: a node selection at a position with no node
|
|
20
|
+
* after it, a selection that points into a different document than the
|
|
21
|
+
* one it is used with, or a duplicate selection JSON id.
|
|
22
|
+
*
|
|
23
|
+
* @since 0.1.0
|
|
24
|
+
* @category errors
|
|
25
|
+
*/
|
|
26
|
+
export declare class SelectionError extends SelectionError_base {}
|
|
27
|
+
/**
|
|
28
|
+
* Union of the errors defined by the state layer.
|
|
29
|
+
*
|
|
30
|
+
* @since 0.1.0
|
|
31
|
+
* @category errors
|
|
32
|
+
*/
|
|
33
|
+
export type StateFailure = StateError | SelectionError;
|
|
34
|
+
/**
|
|
35
|
+
* @since 0.1.0
|
|
36
|
+
* @category guards
|
|
37
|
+
*/
|
|
38
|
+
export declare const isStateFailure: (u: unknown) => u is StateFailure;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
// src/state/errors.ts
|
|
3
|
+
/**
|
|
4
|
+
* Tagged errors raised by the state layer.
|
|
5
|
+
*
|
|
6
|
+
* @since 0.1.0
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* An invalid editor state operation: a state configuration without a
|
|
10
|
+
* schema or document, two different instances of a keyed plugin, a
|
|
11
|
+
* transaction applied to a state it wasn't created for, or invalid
|
|
12
|
+
* JSON field names.
|
|
13
|
+
*
|
|
14
|
+
* @since 0.1.0
|
|
15
|
+
* @category errors
|
|
16
|
+
*/
|
|
17
|
+
var StateError = class extends Schema.TaggedError()("StateError", { message: Schema.String }) {};
|
|
18
|
+
/**
|
|
19
|
+
* An invalid selection: a node selection at a position with no node
|
|
20
|
+
* after it, a selection that points into a different document than the
|
|
21
|
+
* one it is used with, or a duplicate selection JSON id.
|
|
22
|
+
*
|
|
23
|
+
* @since 0.1.0
|
|
24
|
+
* @category errors
|
|
25
|
+
*/
|
|
26
|
+
var SelectionError = class extends Schema.TaggedError()("SelectionError", { message: Schema.String }) {};
|
|
27
|
+
/**
|
|
28
|
+
* @since 0.1.0
|
|
29
|
+
* @category guards
|
|
30
|
+
*/
|
|
31
|
+
const isStateFailure = (u) => u instanceof StateError || u instanceof SelectionError;
|
|
32
|
+
export { SelectionError, StateError, isStateFailure };
|