@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,209 @@
|
|
|
1
|
+
import { baseKeymap } from "../commands/keymaps.js";
|
|
2
|
+
import { deleteSelection, joinBackward, joinDown, joinForward, joinUp, lift, selectAll, selectParentNode, setBlockType, splitBlock, toggleMark, wrapIn } from "../commands/commands.js";
|
|
3
|
+
import { history, redo, undo } from "../history.js";
|
|
4
|
+
import { oneOrMore, seq, zeroOrMore } from "../model/content.js";
|
|
5
|
+
import { marks, nodes } from "../schema-basic.js";
|
|
6
|
+
import { liftListItem, sinkListItem, splitListItem, wrapInList } from "../schema-list/commands.js";
|
|
7
|
+
import { addListNodes } from "../schema-list.js";
|
|
8
|
+
import { Priority, defineCommands, defineKeymap, defineMarkSpec, defineNodeSpec, definePlugin, union, withPriority } from "./extension.js";
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
// src/extensions/defaults.ts
|
|
11
|
+
/**
|
|
12
|
+
* Ready-made extensions wrapping the core modules: base schema nodes
|
|
13
|
+
* and marks, base commands and keymap, history and lists.
|
|
14
|
+
*
|
|
15
|
+
* @since 0.1.0
|
|
16
|
+
*/
|
|
17
|
+
const succeedFalse = Effect.succeed(false);
|
|
18
|
+
const byNodeName = (name, f) => (state, dispatch, view) => {
|
|
19
|
+
const type = state.schema.nodes[name];
|
|
20
|
+
return type ? f(type)(state, dispatch, view) : succeedFalse;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* The top-level `doc` node, containing one or more `block` nodes.
|
|
24
|
+
*
|
|
25
|
+
* @since 0.1.0
|
|
26
|
+
* @category nodes
|
|
27
|
+
*/
|
|
28
|
+
const defineDoc = () => defineNodeSpec("doc", { content: oneOrMore("block") });
|
|
29
|
+
/**
|
|
30
|
+
* The `text` node (in the `inline` group).
|
|
31
|
+
*
|
|
32
|
+
* @since 0.1.0
|
|
33
|
+
* @category nodes
|
|
34
|
+
*/
|
|
35
|
+
const defineText = () => defineNodeSpec("text", { group: "inline" });
|
|
36
|
+
/**
|
|
37
|
+
* The `paragraph` node (`<p>`). It has the highest priority, so that it
|
|
38
|
+
* is the first (and thus default) node of the `block` group.
|
|
39
|
+
*
|
|
40
|
+
* @since 0.1.0
|
|
41
|
+
* @category nodes
|
|
42
|
+
*/
|
|
43
|
+
const defineParagraph = () => withPriority(defineNodeSpec("paragraph", nodes.paragraph), Priority.highest);
|
|
44
|
+
/**
|
|
45
|
+
* The `heading` node, with a `level` attribute (`<h1>`–`<h6>`).
|
|
46
|
+
*
|
|
47
|
+
* @since 0.1.0
|
|
48
|
+
* @category nodes
|
|
49
|
+
*/
|
|
50
|
+
const defineHeading = () => defineNodeSpec("heading", nodes.heading);
|
|
51
|
+
/**
|
|
52
|
+
* The `blockquote` node.
|
|
53
|
+
*
|
|
54
|
+
* @since 0.1.0
|
|
55
|
+
* @category nodes
|
|
56
|
+
*/
|
|
57
|
+
const defineBlockquote = () => defineNodeSpec("blockquote", nodes.blockquote);
|
|
58
|
+
/**
|
|
59
|
+
* The `horizontal_rule` node.
|
|
60
|
+
*
|
|
61
|
+
* @since 0.1.0
|
|
62
|
+
* @category nodes
|
|
63
|
+
*/
|
|
64
|
+
const defineHorizontalRule = () => defineNodeSpec("horizontal_rule", nodes.horizontal_rule);
|
|
65
|
+
/**
|
|
66
|
+
* The `code_block` node.
|
|
67
|
+
*
|
|
68
|
+
* @since 0.1.0
|
|
69
|
+
* @category nodes
|
|
70
|
+
*/
|
|
71
|
+
const defineCodeBlock = () => defineNodeSpec("code_block", nodes.code_block);
|
|
72
|
+
/**
|
|
73
|
+
* The inline `image` node.
|
|
74
|
+
*
|
|
75
|
+
* @since 0.1.0
|
|
76
|
+
* @category nodes
|
|
77
|
+
*/
|
|
78
|
+
const defineImage = () => defineNodeSpec("image", nodes.image);
|
|
79
|
+
/**
|
|
80
|
+
* The inline `hard_break` node.
|
|
81
|
+
*
|
|
82
|
+
* @since 0.1.0
|
|
83
|
+
* @category nodes
|
|
84
|
+
*/
|
|
85
|
+
const defineHardBreak = () => defineNodeSpec("hard_break", nodes.hard_break);
|
|
86
|
+
/**
|
|
87
|
+
* The `link` mark.
|
|
88
|
+
*
|
|
89
|
+
* @since 0.1.0
|
|
90
|
+
* @category marks
|
|
91
|
+
*/
|
|
92
|
+
const defineLink = () => defineMarkSpec("link", marks.link);
|
|
93
|
+
/**
|
|
94
|
+
* The `em` mark.
|
|
95
|
+
*
|
|
96
|
+
* @since 0.1.0
|
|
97
|
+
* @category marks
|
|
98
|
+
*/
|
|
99
|
+
const defineEm = () => defineMarkSpec("em", marks.em);
|
|
100
|
+
/**
|
|
101
|
+
* The `strong` mark.
|
|
102
|
+
*
|
|
103
|
+
* @since 0.1.0
|
|
104
|
+
* @category marks
|
|
105
|
+
*/
|
|
106
|
+
const defineStrong = () => defineMarkSpec("strong", marks.strong);
|
|
107
|
+
/**
|
|
108
|
+
* The `code` mark.
|
|
109
|
+
*
|
|
110
|
+
* @since 0.1.0
|
|
111
|
+
* @category marks
|
|
112
|
+
*/
|
|
113
|
+
const defineCode = () => defineMarkSpec("code", marks.code);
|
|
114
|
+
const insertNode = (type, attrs) => (state, dispatch) => Effect.suspend(() => {
|
|
115
|
+
const { $from } = state.selection;
|
|
116
|
+
let applies = false;
|
|
117
|
+
for (let d = $from.depth; d >= 0 && !applies; d--) {
|
|
118
|
+
const index = $from.index(d);
|
|
119
|
+
applies = $from.node(d).canReplaceWith(index, index, type);
|
|
120
|
+
}
|
|
121
|
+
const node = applies ? type.createAndFillOrNull(attrs) : null;
|
|
122
|
+
if (!node) return succeedFalse;
|
|
123
|
+
return dispatch ? Effect.as(dispatch(state.tr.replaceSelectionWith(node).scrollIntoView()), true) : Effect.succeed(true);
|
|
124
|
+
});
|
|
125
|
+
/**
|
|
126
|
+
* Commands wrapping the core editing commands. Node and mark types are
|
|
127
|
+
* referenced by name and typed against the editor's final schema:
|
|
128
|
+
* `editor.commands.toggleMark("strong")` only type-checks when the
|
|
129
|
+
* schema has a `strong` mark. Commands referring to a type the schema
|
|
130
|
+
* doesn't have don't apply.
|
|
131
|
+
*
|
|
132
|
+
* @since 0.1.0
|
|
133
|
+
* @category commands
|
|
134
|
+
*/
|
|
135
|
+
const defineBaseCommands = () => defineCommands({
|
|
136
|
+
toggleMark: (name, attrs, options) => (state, dispatch, view) => {
|
|
137
|
+
const type = state.schema.marks[name];
|
|
138
|
+
return type ? toggleMark(type, attrs ?? null, options)(state, dispatch, view) : succeedFalse;
|
|
139
|
+
},
|
|
140
|
+
setBlockType: (name, attrs) => byNodeName(name, (type) => setBlockType(type, attrs ?? null)),
|
|
141
|
+
wrapIn: (name, attrs) => byNodeName(name, (type) => wrapIn(type, attrs ?? null)),
|
|
142
|
+
insertNode: (name, attrs) => byNodeName(name, (type) => insertNode(type, attrs ?? null)),
|
|
143
|
+
insertText: (text, from, to) => (state, dispatch) => Effect.suspend(() => dispatch ? Effect.as(dispatch(state.tr.insertTextUnsafe(text, from, to).scrollIntoView()), true) : Effect.succeed(true)),
|
|
144
|
+
deleteSelection: () => deleteSelection,
|
|
145
|
+
selectAll: () => selectAll,
|
|
146
|
+
selectParentNode: () => selectParentNode,
|
|
147
|
+
joinUp: () => joinUp,
|
|
148
|
+
joinDown: () => joinDown,
|
|
149
|
+
joinBackward: () => joinBackward,
|
|
150
|
+
joinForward: () => joinForward,
|
|
151
|
+
lift: () => lift,
|
|
152
|
+
splitBlock: () => splitBlock
|
|
153
|
+
});
|
|
154
|
+
/**
|
|
155
|
+
* The platform's base keymap (`baseKeymap` from `@thomasfosterau/effect-richtext/commands`:
|
|
156
|
+
* Enter, Backspace, Delete, Mod-a, …), at low priority so that other
|
|
157
|
+
* keymaps take precedence.
|
|
158
|
+
*
|
|
159
|
+
* @since 0.1.0
|
|
160
|
+
* @category keymaps
|
|
161
|
+
*/
|
|
162
|
+
const defineBaseKeymap = () => withPriority(defineKeymap(baseKeymap), Priority.low);
|
|
163
|
+
/**
|
|
164
|
+
* Undo history: the `history` plugin, `undo`/`redo` commands, and
|
|
165
|
+
* **Mod-z** (undo), **Mod-y** and **Shift-Mod-z** (redo) bindings.
|
|
166
|
+
* Include it at most once per editor (the history plugin is keyed).
|
|
167
|
+
*
|
|
168
|
+
* @since 0.1.0
|
|
169
|
+
* @category history
|
|
170
|
+
*/
|
|
171
|
+
const defineHistory = (options) => union(definePlugin(history(options)), defineKeymap({
|
|
172
|
+
"Mod-z": undo,
|
|
173
|
+
"Mod-y": redo,
|
|
174
|
+
"Shift-Mod-z": redo
|
|
175
|
+
}), defineCommands({
|
|
176
|
+
undo: () => undo,
|
|
177
|
+
redo: () => redo
|
|
178
|
+
}));
|
|
179
|
+
const listNodes = addListNodes({}, seq("paragraph", zeroOrMore("block")), "block");
|
|
180
|
+
const listItemCommand = (f) => byNodeName("list_item", f);
|
|
181
|
+
/**
|
|
182
|
+
* Lists: the `ordered_list`, `bullet_list` (both in the `block` group)
|
|
183
|
+
* and `list_item` (`paragraph block*`) nodes, the list commands
|
|
184
|
+
* (`wrapInList(name, attrs?)`, `splitListItem`, `liftListItem`,
|
|
185
|
+
* `sinkListItem`), and **Enter** (split item), **Mod-[** (lift) and
|
|
186
|
+
* **Mod-]** (sink) bindings.
|
|
187
|
+
*
|
|
188
|
+
* @since 0.1.0
|
|
189
|
+
* @category lists
|
|
190
|
+
*/
|
|
191
|
+
const defineList = () => union(defineNodeSpec("ordered_list", listNodes.ordered_list), defineNodeSpec("bullet_list", listNodes.bullet_list), defineNodeSpec("list_item", listNodes.list_item), defineKeymap({
|
|
192
|
+
Enter: listItemCommand(splitListItem),
|
|
193
|
+
"Mod-[": listItemCommand(liftListItem),
|
|
194
|
+
"Mod-]": listItemCommand(sinkListItem)
|
|
195
|
+
}), defineCommands({
|
|
196
|
+
wrapInList: (name, attrs) => byNodeName(name, (type) => wrapInList(type, attrs ?? null)),
|
|
197
|
+
splitListItem: () => listItemCommand(splitListItem),
|
|
198
|
+
liftListItem: () => listItemCommand(liftListItem),
|
|
199
|
+
sinkListItem: () => listItemCommand(sinkListItem)
|
|
200
|
+
}));
|
|
201
|
+
/**
|
|
202
|
+
* Everything above: the nodes and marks of `@thomasfosterau/effect-richtext/schema-basic`,
|
|
203
|
+
* lists, base commands, the base keymap and history.
|
|
204
|
+
*
|
|
205
|
+
* @since 0.1.0
|
|
206
|
+
* @category basic
|
|
207
|
+
*/
|
|
208
|
+
const defineBasicExtension = (options) => union(defineDoc(), defineText(), defineParagraph(), defineHeading(), defineBlockquote(), defineHorizontalRule(), defineCodeBlock(), defineImage(), defineHardBreak(), defineLink(), defineEm(), defineStrong(), defineCode(), defineList(), defineBaseCommands(), defineBaseKeymap(), defineHistory(options?.history));
|
|
209
|
+
export { defineBaseCommands, defineBaseKeymap, defineBasicExtension, defineBlockquote, defineCode, defineCodeBlock, defineDoc, defineEm, defineHardBreak, defineHeading, defineHistory, defineHorizontalRule, defineImage, defineLink, defineList, defineParagraph, defineStrong, defineText };
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { ModelError, SchemaDefinitionError } from "../model/errors.js";
|
|
2
|
+
import { AttrsOptional, ChildNames, DocSchema, MarkAttrsInput, MarkNames, MarkSpecOf, NodeAttrsInput, NodeNames, NodeSpecOf } from "../model/schema.js";
|
|
3
|
+
import { Mark } from "../model/mark.js";
|
|
4
|
+
import { Node, NodeJSON, TextNode } from "../model/node.js";
|
|
5
|
+
import "../model.js";
|
|
6
|
+
import { StateFailure } from "../state/errors.js";
|
|
7
|
+
import { DirectEditorProps, EditorView, ViewPlace } from "../view/view.js";
|
|
8
|
+
import { Transaction } from "../state/transaction.js";
|
|
9
|
+
import { Selection } from "../state/selection.js";
|
|
10
|
+
import { EditorState } from "../state/state.js";
|
|
11
|
+
import "../state.js";
|
|
12
|
+
import "../view.js";
|
|
13
|
+
import { CommandCreator, CommandSignature, CommandType, Extension, ExtensionTypes } from "./extension.js";
|
|
14
|
+
import * as Effect from "effect/Effect";
|
|
15
|
+
import * as Option from "effect/Option";
|
|
16
|
+
import * as Scope from "effect/Scope";
|
|
17
|
+
/**
|
|
18
|
+
* The schema of an editor built from an extension with types `T`.
|
|
19
|
+
*
|
|
20
|
+
* @since 0.1.0
|
|
21
|
+
* @category type-level
|
|
22
|
+
*/
|
|
23
|
+
export type SchemaOf<T extends ExtensionTypes> = DocSchema<T["nodes"], T["marks"]>;
|
|
24
|
+
/**
|
|
25
|
+
* The function type of a command, given its command type, the schema
|
|
26
|
+
* and what calling it returns.
|
|
27
|
+
*
|
|
28
|
+
* @since 0.1.0
|
|
29
|
+
* @category type-level
|
|
30
|
+
*/
|
|
31
|
+
export type CommandFn<C extends CommandType, Sc, Ret> = C extends CommandSignature ? (C & {
|
|
32
|
+
readonly Schema: Sc;
|
|
33
|
+
readonly Return: Ret;
|
|
34
|
+
})["signature"] : C extends ReadonlyArray<any> ? (...args: C) => Ret : never;
|
|
35
|
+
/**
|
|
36
|
+
* `editor.commands`: runs a command against the editor's current state
|
|
37
|
+
* (and view, when mounted), dispatching its transaction.
|
|
38
|
+
*
|
|
39
|
+
* @since 0.1.0
|
|
40
|
+
* @category type-level
|
|
41
|
+
*/
|
|
42
|
+
export type EditorCommands<T extends ExtensionTypes> = { readonly [K in keyof T["commands"]]: CommandFn<T["commands"][K], SchemaOf<T>, Effect.Effect<boolean, T["E"], T["R"]>>; };
|
|
43
|
+
/**
|
|
44
|
+
* `editor.can()`: checks whether a command applies, without dispatching.
|
|
45
|
+
*
|
|
46
|
+
* @since 0.1.0
|
|
47
|
+
* @category type-level
|
|
48
|
+
*/
|
|
49
|
+
export type CanCommands<T extends ExtensionTypes> = EditorCommands<T>;
|
|
50
|
+
/**
|
|
51
|
+
* `editor.chain()`: queues commands, which are all applied to a single
|
|
52
|
+
* transaction by `run()`.
|
|
53
|
+
*
|
|
54
|
+
* @since 0.1.0
|
|
55
|
+
* @category type-level
|
|
56
|
+
*/
|
|
57
|
+
export type ChainedCommands<T extends ExtensionTypes> = { readonly [K in keyof T["commands"]]: CommandFn<T["commands"][K], SchemaOf<T>, ChainedCommands<T>>; } & ChainRun<T>;
|
|
58
|
+
/**
|
|
59
|
+
* @since 0.1.0
|
|
60
|
+
* @category type-level
|
|
61
|
+
*/
|
|
62
|
+
export interface ChainRun<T extends ExtensionTypes> {
|
|
63
|
+
/**
|
|
64
|
+
* Run the queued commands into one transaction and dispatch it.
|
|
65
|
+
* Succeeds with `true` when every command applied.
|
|
66
|
+
*/
|
|
67
|
+
readonly run: () => Effect.Effect<boolean, T["E"], T["R"]>;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* A child accepted by a node builder: a node allowed by the node's
|
|
71
|
+
* content expression, or a string (for text) when text is allowed.
|
|
72
|
+
*
|
|
73
|
+
* @since 0.1.0
|
|
74
|
+
* @category type-level
|
|
75
|
+
*/
|
|
76
|
+
export type NodeChild<Sc, N extends string> = Node<Sc & DocSchema<any, any>, ChildNames<Sc, N> & NodeNames<Sc>> | ("text" extends ChildNames<Sc, N> ? string : never) | ReadonlyArray<Node<Sc & DocSchema<any, any>, ChildNames<Sc, N> & NodeNames<Sc>>>;
|
|
77
|
+
/**
|
|
78
|
+
* A node builder (`editor.nodes.<name>`). The attributes may be omitted
|
|
79
|
+
* when they all have defaults.
|
|
80
|
+
*
|
|
81
|
+
* @since 0.1.0
|
|
82
|
+
* @category type-level
|
|
83
|
+
*/
|
|
84
|
+
export type NodeBuilder<Sc extends DocSchema<any, any>, N extends NodeNames<Sc>> = [keyof NodeAttrsInput<Sc, N>] extends [never] ? {
|
|
85
|
+
(attrs: null, ...children: ReadonlyArray<NodeChild<Sc, N>>): Node<Sc, N>;
|
|
86
|
+
(...children: ReadonlyArray<NodeChild<Sc, N>>): Node<Sc, N>;
|
|
87
|
+
} : AttrsOptional<NodeSpecOf<Sc, N>> extends true ? {
|
|
88
|
+
(attrs?: NodeAttrsInput<Sc, N> | null, ...children: ReadonlyArray<NodeChild<Sc, N>>): Node<Sc, N>;
|
|
89
|
+
(...children: ReadonlyArray<NodeChild<Sc, N>>): Node<Sc, N>;
|
|
90
|
+
} : (attrs: NodeAttrsInput<Sc, N>, ...children: ReadonlyArray<NodeChild<Sc, N>>) => Node<Sc, N>;
|
|
91
|
+
/**
|
|
92
|
+
* A mark builder (`editor.marks.<name>`).
|
|
93
|
+
*
|
|
94
|
+
* @since 0.1.0
|
|
95
|
+
* @category type-level
|
|
96
|
+
*/
|
|
97
|
+
export type MarkBuilder<Sc extends DocSchema<any, any>, M extends MarkNames<Sc>> = AttrsOptional<MarkSpecOf<Sc, M>> extends true ? (attrs?: MarkAttrsInput<Sc, M> | null) => Mark<Sc, M> : (attrs: MarkAttrsInput<Sc, M>) => Mark<Sc, M>;
|
|
98
|
+
/**
|
|
99
|
+
* @since 0.1.0
|
|
100
|
+
* @category type-level
|
|
101
|
+
*/
|
|
102
|
+
export type NodeBuilders<Sc extends DocSchema<any, any>> = { readonly [N in NodeNames<Sc>]: NodeBuilder<Sc, N>; };
|
|
103
|
+
/**
|
|
104
|
+
* @since 0.1.0
|
|
105
|
+
* @category type-level
|
|
106
|
+
*/
|
|
107
|
+
export type MarkBuilders<Sc extends DocSchema<any, any>> = { readonly [M in MarkNames<Sc>]: MarkBuilder<Sc, M>; };
|
|
108
|
+
/**
|
|
109
|
+
* Content accepted by `createEditor` and `setContent`: a document node,
|
|
110
|
+
* its JSON representation, or an HTML string (parsed with the schema's
|
|
111
|
+
* parse rules; needs a DOM `document`).
|
|
112
|
+
*
|
|
113
|
+
* @since 0.1.0
|
|
114
|
+
* @category models
|
|
115
|
+
*/
|
|
116
|
+
export type EditorContent<Sc extends DocSchema<any, any>> = Node<Sc> | NodeJSON | string;
|
|
117
|
+
/**
|
|
118
|
+
* Options for `createEditor`.
|
|
119
|
+
*
|
|
120
|
+
* @since 0.1.0
|
|
121
|
+
* @category models
|
|
122
|
+
*/
|
|
123
|
+
export interface EditorOptions<Sc extends DocSchema<any, any>> {
|
|
124
|
+
/** The initial document. Defaults to an empty document. */
|
|
125
|
+
readonly doc?: EditorContent<Sc> | undefined;
|
|
126
|
+
/** The initial selection. Defaults to the start of the document. */
|
|
127
|
+
readonly selection?: ((doc: Node<Sc>) => Selection<Sc>) | undefined;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* The errors `createEditor` can fail with besides those of the
|
|
131
|
+
* extension's plugins: invalid specs (`SchemaDefinitionError`), invalid
|
|
132
|
+
* initial content (`ModelError`), or a state that can't be created.
|
|
133
|
+
*
|
|
134
|
+
* @since 0.1.0
|
|
135
|
+
* @category models
|
|
136
|
+
*/
|
|
137
|
+
export type CreateEditorError = SchemaDefinitionError | ModelError | StateFailure;
|
|
138
|
+
/**
|
|
139
|
+
* Options for `Editor.mount`: the view's props, without `state`.
|
|
140
|
+
*
|
|
141
|
+
* @since 0.1.0
|
|
142
|
+
* @category models
|
|
143
|
+
*/
|
|
144
|
+
export type MountProps<Sc extends DocSchema<any, any>, R, E> = Omit<DirectEditorProps<Sc, R, E>, "state">;
|
|
145
|
+
/**
|
|
146
|
+
* @since 0.1.0
|
|
147
|
+
* @category symbols
|
|
148
|
+
*/
|
|
149
|
+
export declare const EditorTypeId: unique symbol;
|
|
150
|
+
/**
|
|
151
|
+
* @since 0.1.0
|
|
152
|
+
* @category symbols
|
|
153
|
+
*/
|
|
154
|
+
export type EditorTypeId = typeof EditorTypeId;
|
|
155
|
+
/**
|
|
156
|
+
* An editor created from an extension by `createEditor`. It owns the
|
|
157
|
+
* current `EditorState`, and, while mounted, an `EditorView` (which then
|
|
158
|
+
* holds the current state).
|
|
159
|
+
*
|
|
160
|
+
* @since 0.1.0
|
|
161
|
+
* @category models
|
|
162
|
+
*/
|
|
163
|
+
export declare class Editor<T extends ExtensionTypes> {
|
|
164
|
+
/** The editor's schema, built from the extension's node and mark specs. */
|
|
165
|
+
readonly schema: SchemaOf<T>;
|
|
166
|
+
readonly [EditorTypeId]: {
|
|
167
|
+
readonly _T: (_: never) => T;
|
|
168
|
+
};
|
|
169
|
+
private _state;
|
|
170
|
+
private _view;
|
|
171
|
+
private readonly creators;
|
|
172
|
+
/** Typed node builders: `editor.nodes.heading({ level: 2 }, "Title")`. Throw on invalid content. */
|
|
173
|
+
readonly nodes: NodeBuilders<SchemaOf<T>>;
|
|
174
|
+
/** Typed mark builders: `editor.marks.link({ href })`. Throw on invalid attributes. */
|
|
175
|
+
readonly marks: MarkBuilders<SchemaOf<T>>;
|
|
176
|
+
/** The editor's commands. */
|
|
177
|
+
readonly commands: EditorCommands<T>;
|
|
178
|
+
/** @internal */
|
|
179
|
+
constructor(
|
|
180
|
+
/** The editor's schema, built from the extension's node and mark specs. */
|
|
181
|
+
schema: SchemaOf<T>, state: EditorState<SchemaOf<T>, T["R"], T["E"]>, creators: Record<string, CommandCreator>);
|
|
182
|
+
/** The current editor state (the view's state while mounted). */
|
|
183
|
+
get state(): EditorState<SchemaOf<T>, T["R"], T["E"]>;
|
|
184
|
+
/** The view, while the editor is mounted. */
|
|
185
|
+
get view(): Option.Option<EditorView<SchemaOf<T>, T["R"], T["E"]>>;
|
|
186
|
+
/** Whether the editor is currently mounted. */
|
|
187
|
+
get mounted(): boolean;
|
|
188
|
+
/**
|
|
189
|
+
* Mount the editor: create an `EditorView` (with `EditorView.make`)
|
|
190
|
+
* for the current state in `place`. The view is destroyed, and the
|
|
191
|
+
* editor unmounted, when the scope closes (or on `unmount`). Mounting
|
|
192
|
+
* an already mounted editor first unmounts it.
|
|
193
|
+
*/
|
|
194
|
+
mount(place: ViewPlace, props?: MountProps<SchemaOf<T>, T["R"], T["E"]>): Effect.Effect<void, never, Scope.Scope | T["R"]>;
|
|
195
|
+
/** Destroy the view, if mounted. The editor keeps the view's last state. */
|
|
196
|
+
get unmount(): Effect.Effect<void>;
|
|
197
|
+
private detach;
|
|
198
|
+
/**
|
|
199
|
+
* Dispatch a transaction: through the view when mounted (honouring its
|
|
200
|
+
* `dispatchTransaction` prop), otherwise by applying it to the
|
|
201
|
+
* editor's state. Fails with the plugins' errors.
|
|
202
|
+
*/
|
|
203
|
+
dispatch(tr: Transaction<SchemaOf<T>>): Effect.Effect<void, T["E"], T["R"]>;
|
|
204
|
+
private runCommand;
|
|
205
|
+
/** Check whether commands apply to the current state, without dispatching. */
|
|
206
|
+
can(): CanCommands<T>;
|
|
207
|
+
/**
|
|
208
|
+
* Queue commands to apply them in a single transaction. Each command
|
|
209
|
+
* sees the document, selection and stored marks produced by the
|
|
210
|
+
* previous ones (through a state whose `tr` is the shared
|
|
211
|
+
* transaction). `run()` runs every queued command, then dispatches
|
|
212
|
+
* the transaction (when any command changed it), and succeeds with
|
|
213
|
+
* `true` when all commands applied.
|
|
214
|
+
*/
|
|
215
|
+
chain(): ChainedCommands<T>;
|
|
216
|
+
/**
|
|
217
|
+
* Replace the document's content (through a transaction, so plugins
|
|
218
|
+
* like the history see it). Accepts a node, its JSON, or HTML.
|
|
219
|
+
*/
|
|
220
|
+
setContent(content: EditorContent<SchemaOf<T>>): Effect.Effect<void, ModelError | T["E"], T["R"]>;
|
|
221
|
+
/** The current document as JSON. */
|
|
222
|
+
getDocJSON(): NodeJSON;
|
|
223
|
+
/** Create a text node with the given marks. Throws for empty strings. */
|
|
224
|
+
text(text: string, ...marks: ReadonlyArray<Mark<SchemaOf<T>>>): TextNode<SchemaOf<T>>;
|
|
225
|
+
private nodeBuilder;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Create an editor from an extension: builds the schema from the merged
|
|
229
|
+
* node and mark specs (ordered by priority, then declaration), resolves
|
|
230
|
+
* the plugins (keymaps included, same order) and creates the initial
|
|
231
|
+
* state. The editor isn't mounted; see `Editor.mount`.
|
|
232
|
+
*
|
|
233
|
+
* @since 0.1.0
|
|
234
|
+
* @category constructors
|
|
235
|
+
*/
|
|
236
|
+
export declare const createEditor: <T extends ExtensionTypes>(extension: Extension<T>, options?: EditorOptions<SchemaOf<T>>) => Effect.Effect<Editor<T>, CreateEditorError | T["E"], T["R"]>;
|
|
237
|
+
/**
|
|
238
|
+
* Like `createEditor`, but runs synchronously and throws failures. Only
|
|
239
|
+
* available for extensions that require no services.
|
|
240
|
+
*
|
|
241
|
+
* @since 0.1.0
|
|
242
|
+
* @category constructors
|
|
243
|
+
*/
|
|
244
|
+
export declare const createEditorUnsafe: <T extends ExtensionTypes & {
|
|
245
|
+
readonly R: never;
|
|
246
|
+
}>(extension: Extension<T>, options?: EditorOptions<SchemaOf<T>>) => Editor<T>;
|