@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.
Files changed (176) hide show
  1. package/LICENSE +48 -0
  2. package/README.md +118 -2
  3. package/dist/_virtual/_rolldown/runtime.js +12 -0
  4. package/dist/commands/commands.d.ts +323 -0
  5. package/dist/commands/commands.js +722 -0
  6. package/dist/commands/internal.js +43 -0
  7. package/dist/commands/keymaps.d.ts +46 -0
  8. package/dist/commands/keymaps.js +64 -0
  9. package/dist/commands.d.ts +3 -0
  10. package/dist/commands.js +3 -0
  11. package/dist/compat/commands.d.ts +250 -0
  12. package/dist/compat/commands.js +275 -0
  13. package/dist/compat/internal/core.d.ts +20 -0
  14. package/dist/compat/internal/core.js +148 -0
  15. package/dist/compat/internal/props.js +82 -0
  16. package/dist/compat/keymap.d.ts +21 -0
  17. package/dist/compat/keymap.js +38 -0
  18. package/dist/compat/model.d.ts +893 -0
  19. package/dist/compat/model.js +1212 -0
  20. package/dist/compat/orderedmap.d.ts +74 -0
  21. package/dist/compat/orderedmap.js +124 -0
  22. package/dist/compat/schema-basic.d.ts +38 -0
  23. package/dist/compat/schema-basic.js +238 -0
  24. package/dist/compat/schema-list.d.ts +81 -0
  25. package/dist/compat/schema-list.js +156 -0
  26. package/dist/compat/state.d.ts +415 -0
  27. package/dist/compat/state.js +689 -0
  28. package/dist/compat/test-builder.d.ts +98 -0
  29. package/dist/compat/test-builder.js +197 -0
  30. package/dist/compat/transform.d.ts +458 -0
  31. package/dist/compat/transform.js +803 -0
  32. package/dist/compat/view.d.ts +411 -0
  33. package/dist/compat/view.js +409 -0
  34. package/dist/dropcursor.d.ts +46 -0
  35. package/dist/dropcursor.js +176 -0
  36. package/dist/extensions/defaults.d.ts +716 -0
  37. package/dist/extensions/defaults.js +209 -0
  38. package/dist/extensions/editor.d.ts +246 -0
  39. package/dist/extensions/editor.js +271 -0
  40. package/dist/extensions/extension.d.ts +375 -0
  41. package/dist/extensions/extension.js +233 -0
  42. package/dist/extensions.d.ts +4 -0
  43. package/dist/extensions.js +4 -0
  44. package/dist/gapcursor.d.ts +66 -0
  45. package/dist/gapcursor.js +273 -0
  46. package/dist/history.d.ts +178 -0
  47. package/dist/history.js +412 -0
  48. package/dist/html.d.ts +158 -0
  49. package/dist/html.js +164 -0
  50. package/dist/inputrules.d.ts +271 -0
  51. package/dist/inputrules.js +321 -0
  52. package/dist/internal/attempt.js +15 -0
  53. package/dist/internal/json.js +29 -0
  54. package/dist/keymap/keymap.d.ts +130 -0
  55. package/dist/keymap/keymap.js +159 -0
  56. package/dist/keymap.d.ts +2 -0
  57. package/dist/keymap.js +1 -0
  58. package/dist/markdown/errors.d.ts +23 -0
  59. package/dist/markdown/errors.js +26 -0
  60. package/dist/markdown/from_markdown.d.ts +185 -0
  61. package/dist/markdown/from_markdown.js +266 -0
  62. package/dist/markdown/schema.d.ts +522 -0
  63. package/dist/markdown/schema.js +292 -0
  64. package/dist/markdown/to_markdown.d.ts +251 -0
  65. package/dist/markdown/to_markdown.js +413 -0
  66. package/dist/markdown.d.ts +5 -0
  67. package/dist/markdown.js +5 -0
  68. package/dist/model/attrsCodec.js +48 -0
  69. package/dist/model/comparedeep.js +17 -0
  70. package/dist/model/content.d.ts +232 -0
  71. package/dist/model/content.js +630 -0
  72. package/dist/model/diff.js +66 -0
  73. package/dist/model/dom.d.ts +3 -0
  74. package/dist/model/errors.d.ts +90 -0
  75. package/dist/model/errors.js +76 -0
  76. package/dist/model/fragment.d.ts +131 -0
  77. package/dist/model/fragment.js +262 -0
  78. package/dist/model/from_dom.d.ts +299 -0
  79. package/dist/model/from_dom.js +618 -0
  80. package/dist/model/json.d.ts +37 -0
  81. package/dist/model/json.js +126 -0
  82. package/dist/model/mark.d.ts +73 -0
  83. package/dist/model/mark.js +121 -0
  84. package/dist/model/node.d.ts +267 -0
  85. package/dist/model/node.js +434 -0
  86. package/dist/model/replace.d.ts +78 -0
  87. package/dist/model/replace.js +207 -0
  88. package/dist/model/resolvedpos.d.ts +196 -0
  89. package/dist/model/resolvedpos.js +305 -0
  90. package/dist/model/schema.d.ts +740 -0
  91. package/dist/model/schema.js +451 -0
  92. package/dist/model/to_dom.d.ts +169 -0
  93. package/dist/model/to_dom.js +238 -0
  94. package/dist/model.d.ts +12 -0
  95. package/dist/model.js +12 -0
  96. package/dist/placeholder.d.ts +53 -0
  97. package/dist/placeholder.js +79 -0
  98. package/dist/reactive/observer.d.ts +54 -0
  99. package/dist/reactive/observer.js +61 -0
  100. package/dist/reactive/selectors.d.ts +22 -0
  101. package/dist/reactive/selectors.js +61 -0
  102. package/dist/reactive/stateref.d.ts +72 -0
  103. package/dist/reactive/stateref.js +71 -0
  104. package/dist/reactive/streams.d.ts +83 -0
  105. package/dist/reactive/streams.js +85 -0
  106. package/dist/reactive.d.ts +16 -0
  107. package/dist/reactive.js +26 -0
  108. package/dist/schema-basic.d.ts +448 -0
  109. package/dist/schema-basic.js +269 -0
  110. package/dist/schema-list/commands.d.ts +66 -0
  111. package/dist/schema-list/commands.js +203 -0
  112. package/dist/schema-list.d.ts +92 -0
  113. package/dist/schema-list.js +100 -0
  114. package/dist/state/errors.d.ts +39 -0
  115. package/dist/state/errors.js +32 -0
  116. package/dist/state/plugin.d.ts +232 -0
  117. package/dist/state/plugin.js +82 -0
  118. package/dist/state/selection.d.ts +297 -0
  119. package/dist/state/selection.js +486 -0
  120. package/dist/state/state.d.ts +212 -0
  121. package/dist/state/state.js +489 -0
  122. package/dist/state/transaction.d.ts +145 -0
  123. package/dist/state/transaction.js +195 -0
  124. package/dist/state.d.ts +6 -0
  125. package/dist/state.js +6 -0
  126. package/dist/test-builder.d.ts +3582 -0
  127. package/dist/test-builder.js +239 -0
  128. package/dist/transform/attr_step.d.ts +60 -0
  129. package/dist/transform/attr_step.js +105 -0
  130. package/dist/transform/errors.d.ts +50 -0
  131. package/dist/transform/errors.js +35 -0
  132. package/dist/transform/map.d.ts +182 -0
  133. package/dist/transform/map.js +280 -0
  134. package/dist/transform/mark.js +98 -0
  135. package/dist/transform/mark_set_step.js +69 -0
  136. package/dist/transform/mark_step.d.ts +113 -0
  137. package/dist/transform/mark_step.js +225 -0
  138. package/dist/transform/replace.d.ts +18 -0
  139. package/dist/transform/replace.js +381 -0
  140. package/dist/transform/replace_step.d.ts +109 -0
  141. package/dist/transform/replace_step.js +175 -0
  142. package/dist/transform/step.d.ts +157 -0
  143. package/dist/transform/step.js +168 -0
  144. package/dist/transform/structure.d.ts +89 -0
  145. package/dist/transform/structure.js +350 -0
  146. package/dist/transform/transform.d.ts +248 -0
  147. package/dist/transform/transform.js +373 -0
  148. package/dist/transform.d.ts +10 -0
  149. package/dist/transform.js +10 -0
  150. package/dist/view/browser.js +39 -0
  151. package/dist/view/capturekeys.js +282 -0
  152. package/dist/view/clipboard.d.ts +8 -0
  153. package/dist/view/clipboard.js +245 -0
  154. package/dist/view/decoration.d.ts +339 -0
  155. package/dist/view/decoration.js +566 -0
  156. package/dist/view/dom.d.ts +18 -0
  157. package/dist/view/dom.js +140 -0
  158. package/dist/view/domchange.js +295 -0
  159. package/dist/view/domcoords.d.ts +22 -0
  160. package/dist/view/domcoords.js +448 -0
  161. package/dist/view/domobserver.d.ts +47 -0
  162. package/dist/view/domobserver.js +328 -0
  163. package/dist/view/errors.d.ts +18 -0
  164. package/dist/view/errors.js +21 -0
  165. package/dist/view/input.d.ts +58 -0
  166. package/dist/view/input.js +704 -0
  167. package/dist/view/selection.js +198 -0
  168. package/dist/view/view.d.ts +699 -0
  169. package/dist/view/view.js +623 -0
  170. package/dist/view/viewdesc.d.ts +236 -0
  171. package/dist/view/viewdesc.js +1205 -0
  172. package/dist/view-css.d.ts +43 -0
  173. package/dist/view-css.js +124 -0
  174. package/dist/view.d.ts +6 -0
  175. package/dist/view.js +4 -0
  176. package/package.json +206 -3
@@ -0,0 +1,271 @@
1
+ import { fromHTMLUnsafe } from "../html.js";
2
+ import { attempt } from "../internal/attempt.js";
3
+ import { DocSchema } from "../model/schema.js";
4
+ import { Fragment } from "../model/fragment.js";
5
+ import { isModelError } from "../model/errors.js";
6
+ import { Mark } from "../model/mark.js";
7
+ import { Node } from "../model/node.js";
8
+ import { EditorState, runSyncUnsafe } from "../state/state.js";
9
+ import { StateError, isStateFailure } from "../state/errors.js";
10
+ import { EditorView } from "../view/view.js";
11
+ import { flatten, resolvePlugins } from "./extension.js";
12
+ import * as Effect from "effect/Effect";
13
+ import * as Option from "effect/Option";
14
+ // src/extensions/editor.ts
15
+ /**
16
+ * The `Editor`: an editor state, an optional view, and typed commands
17
+ * and builders, created from an extension.
18
+ *
19
+ * @since 0.1.0
20
+ */
21
+ /**
22
+ * An editor state seen by chained commands. It shares one transaction
23
+ * between all commands in a chain: its `doc`, `selection` and stored
24
+ * marks are the transaction's current ones, and its `tr` is the shared
25
+ * transaction itself. Plugin state is that of the state the chain
26
+ * started from.
27
+ *
28
+ * @internal
29
+ */
30
+ var ChainableState = class extends EditorState {
31
+ constructor(base, chainTr) {
32
+ super(base.config, base.slots);
33
+ this.chainTr = chainTr;
34
+ }
35
+ get doc() {
36
+ return this.chainTr.doc;
37
+ }
38
+ get selection() {
39
+ return this.chainTr.selection;
40
+ }
41
+ get storedMarksOrNull() {
42
+ return this.chainTr.storedMarksOrNull;
43
+ }
44
+ get tr() {
45
+ return this.chainTr;
46
+ }
47
+ };
48
+ const foldInto = (target, tr) => {
49
+ if (tr === target) return;
50
+ if (!tr.before.eq(target.doc)) throw new StateError({ message: "A chained command dispatched a transaction that doesn't match the chain" });
51
+ for (const step of tr.steps) target.stepUnsafe(step);
52
+ if (tr.selectionSet) target.setSelectionUnsafe(tr.selection.map(target.doc, target.mapping.slice(target.steps.length)));
53
+ if (tr.storedMarksSet) target.setStoredMarks(tr.storedMarksOrNull);
54
+ if (tr.scrolledIntoView) target.scrollIntoView();
55
+ const meta = tr.meta;
56
+ for (const key in meta) target.setMeta(key, meta[key]);
57
+ };
58
+ const isPlainObject = (u) => {
59
+ if (u === null || typeof u !== "object" || Array.isArray(u)) return false;
60
+ const proto = Object.getPrototypeOf(u);
61
+ return proto === Object.prototype || proto === null;
62
+ };
63
+ const dieOnStateFailure = (effect) => Effect.catchIf(effect, isStateFailure, (e) => Effect.die(e));
64
+ /**
65
+ * @since 0.1.0
66
+ * @category symbols
67
+ */
68
+ const EditorTypeId = Symbol.for("effect-richtext/extensions/Editor");
69
+ /**
70
+ * An editor created from an extension by `createEditor`. It owns the
71
+ * current `EditorState`, and, while mounted, an `EditorView` (which then
72
+ * holds the current state).
73
+ *
74
+ * @since 0.1.0
75
+ * @category models
76
+ */
77
+ var Editor = class {
78
+ /** @internal */
79
+ constructor(schema, state, creators) {
80
+ this.schema = schema;
81
+ this._view = void 0;
82
+ this._state = state;
83
+ this.creators = creators;
84
+ const nodes = {};
85
+ for (const name in schema.nodes) nodes[name] = this.nodeBuilder(name);
86
+ this.nodes = nodes;
87
+ const marks = {};
88
+ for (const name in schema.marks) marks[name] = (attrs) => schema.markUnsafe(name, attrs);
89
+ this.marks = marks;
90
+ const commands = {};
91
+ for (const name in creators) commands[name] = (...args) => Effect.suspend(() => this.runCommand(creators[name](...args), true));
92
+ this.commands = commands;
93
+ }
94
+ /** The current editor state (the view's state while mounted). */
95
+ get state() {
96
+ return this._view ? this._view.state : this._state;
97
+ }
98
+ /** The view, while the editor is mounted. */
99
+ get view() {
100
+ return Option.fromUndefinedOr(this._view);
101
+ }
102
+ /** Whether the editor is currently mounted. */
103
+ get mounted() {
104
+ return this._view !== void 0;
105
+ }
106
+ /**
107
+ * Mount the editor: create an `EditorView` (with `EditorView.make`)
108
+ * for the current state in `place`. The view is destroyed, and the
109
+ * editor unmounted, when the scope closes (or on `unmount`). Mounting
110
+ * an already mounted editor first unmounts it.
111
+ */
112
+ mount(place, props) {
113
+ return Effect.gen({ self: this }, function* () {
114
+ yield* this.unmount;
115
+ const view = yield* EditorView.make(place, {
116
+ ...props,
117
+ state: this.state
118
+ });
119
+ this._view = view;
120
+ yield* Effect.addFinalizer(() => Effect.sync(() => this.detach(view)));
121
+ });
122
+ }
123
+ /** Destroy the view, if mounted. The editor keeps the view's last state. */
124
+ get unmount() {
125
+ return Effect.sync(() => {
126
+ const view = this._view;
127
+ if (view) {
128
+ this.detach(view);
129
+ view.destroy();
130
+ }
131
+ });
132
+ }
133
+ detach(view) {
134
+ if (this._view !== view) return;
135
+ this._state = view.state;
136
+ this._view = void 0;
137
+ }
138
+ /**
139
+ * Dispatch a transaction: through the view when mounted (honouring its
140
+ * `dispatchTransaction` prop), otherwise by applying it to the
141
+ * editor's state. Fails with the plugins' errors.
142
+ */
143
+ dispatch(tr) {
144
+ return Effect.suspend(() => {
145
+ const view = this._view;
146
+ if (view) return dieOnStateFailure(view.tryDispatch(tr));
147
+ return dieOnStateFailure(Effect.map(this._state.apply(tr), (state) => {
148
+ this._state = state;
149
+ }));
150
+ });
151
+ }
152
+ runCommand(command, dispatching) {
153
+ if (!dispatching) return command(this.state, void 0, this._view);
154
+ return Effect.flatMap(Effect.context(), (context) => {
155
+ const dispatch = (tr) => Effect.provideContext(this.dispatch(tr), context);
156
+ return command(this.state, dispatch, this._view);
157
+ });
158
+ }
159
+ /** Check whether commands apply to the current state, without dispatching. */
160
+ can() {
161
+ const result = {};
162
+ for (const name in this.creators) result[name] = (...args) => Effect.suspend(() => this.runCommand(this.creators[name](...args), false));
163
+ return result;
164
+ }
165
+ /**
166
+ * Queue commands to apply them in a single transaction. Each command
167
+ * sees the document, selection and stored marks produced by the
168
+ * previous ones (through a state whose `tr` is the shared
169
+ * transaction). `run()` runs every queued command, then dispatches
170
+ * the transaction (when any command changed it), and succeeds with
171
+ * `true` when all commands applied.
172
+ */
173
+ chain() {
174
+ const queue = [];
175
+ const chain = {};
176
+ for (const name in this.creators) {
177
+ if (name === "run") continue;
178
+ chain[name] = (...args) => {
179
+ queue.push(this.creators[name](...args));
180
+ return chain;
181
+ };
182
+ }
183
+ chain.run = () => Effect.gen({ self: this }, function* () {
184
+ const state = this.state;
185
+ const tr = state.tr;
186
+ const chained = new ChainableState(state, tr);
187
+ const dispatch = (t) => Effect.sync(() => foldInto(tr, t));
188
+ let all = true;
189
+ for (const command of queue) if (!(yield* command(chained, dispatch, this._view))) all = false;
190
+ if (tr.docChanged || tr.selectionSet || tr.storedMarksSet || tr.scrolledIntoView || !tr.isGeneric) yield* this.dispatch(tr);
191
+ return all;
192
+ });
193
+ return chain;
194
+ }
195
+ /**
196
+ * Replace the document's content (through a transaction, so plugins
197
+ * like the history see it). Accepts a node, its JSON, or HTML.
198
+ */
199
+ setContent(content) {
200
+ return Effect.flatMap(attempt(() => parseContent(this.schema, content), isModelError), (doc) => Effect.suspend(() => {
201
+ const tr = this.state.tr;
202
+ tr.replaceWithUnsafe(0, tr.doc.content.size, doc.content);
203
+ return this.dispatch(tr);
204
+ }));
205
+ }
206
+ /** The current document as JSON. */
207
+ getDocJSON() {
208
+ return this.state.doc.toJSON();
209
+ }
210
+ /** Create a text node with the given marks. Throws for empty strings. */
211
+ text(text, ...marks) {
212
+ return this.schema.textUnsafe(text, marks.length ? Mark.setFrom(marks) : null);
213
+ }
214
+ nodeBuilder(name) {
215
+ const type = this.schema.nodes[name];
216
+ return (...args) => {
217
+ let attrs = null;
218
+ if (args.length && (args[0] === null || isPlainObject(args[0]))) attrs = args.shift();
219
+ const children = [];
220
+ const add = (child) => {
221
+ if (typeof child === "string") {
222
+ if (child) children.push(this.schema.textUnsafe(child));
223
+ } else if (Array.isArray(child)) child.forEach(add);
224
+ else if (child instanceof Fragment) child.forEach((n) => children.push(n));
225
+ else if (child instanceof Node) children.push(child);
226
+ else throw new TypeError("Invalid child passed to a node builder: " + String(child));
227
+ };
228
+ args.forEach(add);
229
+ return type.createCheckedUnsafe(attrs, children);
230
+ };
231
+ }
232
+ };
233
+ const parseContent = (schema, content) => {
234
+ if (content instanceof Node) return content.type.schema === schema ? content : schema.nodeFromJSONUnsafe(content.toJSON());
235
+ if (typeof content === "string") return fromHTMLUnsafe(schema, content);
236
+ return schema.nodeFromJSONUnsafe(content);
237
+ };
238
+ /**
239
+ * Create an editor from an extension: builds the schema from the merged
240
+ * node and mark specs (ordered by priority, then declaration), resolves
241
+ * the plugins (keymaps included, same order) and creates the initial
242
+ * state. The editor isn't mounted; see `Editor.mount`.
243
+ *
244
+ * @since 0.1.0
245
+ * @category constructors
246
+ */
247
+ const createEditor = (extension, options = {}) => Effect.gen(function* () {
248
+ const flat = flatten(extension);
249
+ const schema = yield* DocSchema.make({
250
+ nodes: flat.nodes,
251
+ marks: flat.marks
252
+ });
253
+ const plugins = resolvePlugins(flat.plugins, schema);
254
+ const doc = options.doc === void 0 ? void 0 : yield* attempt(() => parseContent(schema, options.doc), isModelError);
255
+ const config = {
256
+ schema,
257
+ doc,
258
+ selection: doc && options.selection ? options.selection(doc) : void 0,
259
+ plugins
260
+ };
261
+ return new Editor(schema, yield* EditorState.create(config), flat.commands);
262
+ });
263
+ /**
264
+ * Like `createEditor`, but runs synchronously and throws failures. Only
265
+ * available for extensions that require no services.
266
+ *
267
+ * @since 0.1.0
268
+ * @category constructors
269
+ */
270
+ const createEditorUnsafe = (extension, options = {}) => runSyncUnsafe(createEditor(extension, options));
271
+ export { Editor, EditorTypeId, createEditor, createEditorUnsafe };
@@ -0,0 +1,375 @@
1
+ import { AnySchema, MarkSpec, MarkSpecs, NodeSpec, NodeSpecs } from "../model/schema.js";
2
+ import "../keymap.js";
3
+ import { Command } from "../state/transaction.js";
4
+ import { AnyPlugin, Plugin } from "../state/plugin.js";
5
+ import "../model.js";
6
+ import { Bindings, BindingsError, BindingsRequirements } from "../keymap/keymap.js";
7
+ import "../state.js";
8
+ import * as Effect from "effect/Effect";
9
+ /**
10
+ * Extension priorities. Within a merged extension, facets with a higher
11
+ * priority come first: their node and mark specs come earlier in the
12
+ * schema (which matters for the default node of a group and for parse
13
+ * rule precedence), their plugins and keymaps come earlier in the
14
+ * plugin list (so their key bindings and props take precedence), and
15
+ * their commands win over commands with the same name. Facets with the
16
+ * same priority keep their declaration order.
17
+ *
18
+ * @since 0.1.0
19
+ * @category models
20
+ */
21
+ export declare const Priority: {
22
+ readonly lowest: 0;
23
+ readonly low: 1;
24
+ readonly default: 2;
25
+ readonly high: 3;
26
+ readonly highest: 4;
27
+ };
28
+ /**
29
+ * @since 0.1.0
30
+ * @category models
31
+ */
32
+ export type Priority = (typeof Priority)[keyof typeof Priority];
33
+ /**
34
+ * A command whose argument types depend on the final (merged) schema,
35
+ * described as a type lambda: `this["Schema"]` is the editor's schema
36
+ * and `this["Return"]` the type the call returns (an Effect for
37
+ * `editor.commands`, the chain for `editor.chain()`).
38
+ *
39
+ * ```ts skip-type-checking
40
+ * interface ToggleMark extends CommandSignature {
41
+ * readonly signature: <M extends MarkNames<this["Schema"]>>(mark: M) => this["Return"]
42
+ * }
43
+ * ```
44
+ *
45
+ * @since 0.1.0
46
+ * @category type-level
47
+ */
48
+ export interface CommandSignature {
49
+ readonly Schema: unknown;
50
+ readonly Return: unknown;
51
+ readonly signature: (...args: any) => unknown;
52
+ }
53
+ /**
54
+ * The type-level description of a command: its argument tuple, or a
55
+ * `CommandSignature` for schema-dependent commands.
56
+ *
57
+ * @since 0.1.0
58
+ * @category type-level
59
+ */
60
+ export type CommandType = ReadonlyArray<any> | CommandSignature;
61
+ /**
62
+ * @since 0.1.0
63
+ * @category type-level
64
+ */
65
+ export interface CommandTypes {
66
+ readonly [name: string]: CommandType;
67
+ }
68
+ /**
69
+ * What an extension contributes at the type level: node specs, mark
70
+ * specs, commands (name to argument types), and the errors (`E`) and
71
+ * requirements (`R`) of its plugins and commands.
72
+ *
73
+ * @since 0.1.0
74
+ * @category type-level
75
+ */
76
+ export interface ExtensionTypes {
77
+ readonly nodes: NodeSpecs;
78
+ readonly marks: MarkSpecs;
79
+ readonly commands: CommandTypes;
80
+ readonly E: unknown;
81
+ readonly R: unknown;
82
+ }
83
+ /**
84
+ * The types of an extension that contributes nothing.
85
+ *
86
+ * @since 0.1.0
87
+ * @category type-level
88
+ */
89
+ export interface EmptyTypes {
90
+ readonly nodes: {};
91
+ readonly marks: {};
92
+ readonly commands: {};
93
+ readonly E: never;
94
+ readonly R: never;
95
+ }
96
+ type Simplify<A> = { [K in keyof A]: A[K]; } & {};
97
+ type Cast<A, B> = A extends B ? A : never;
98
+ type UnionToIntersection<U> = (U extends any ? (u: U) => void : never) extends ((i: infer I) => void) ? I : never;
99
+ /**
100
+ * Merge a union of extension types: node, mark and command records are
101
+ * intersected, `E` and `R` are unions.
102
+ *
103
+ * @since 0.1.0
104
+ * @category type-level
105
+ */
106
+ export type MergeTypes<T extends ExtensionTypes> = {
107
+ readonly nodes: Cast<Simplify<UnionToIntersection<T["nodes"]>>, NodeSpecs>;
108
+ readonly marks: Cast<Simplify<UnionToIntersection<T["marks"]>>, MarkSpecs>;
109
+ readonly commands: Cast<Simplify<UnionToIntersection<T["commands"]>>, CommandTypes>;
110
+ readonly E: T["E"];
111
+ readonly R: T["R"];
112
+ };
113
+ /**
114
+ * The types of an extension.
115
+ *
116
+ * @since 0.1.0
117
+ * @category type-level
118
+ */
119
+ export type TypesOf<X> = X extends Extension<infer T> ? T : never;
120
+ /**
121
+ * The node specs contributed by an extension.
122
+ *
123
+ * @since 0.1.0
124
+ * @category type-level
125
+ */
126
+ export type ExtensionNodes<X> = TypesOf<X>["nodes"];
127
+ /**
128
+ * The mark specs contributed by an extension.
129
+ *
130
+ * @since 0.1.0
131
+ * @category type-level
132
+ */
133
+ export type ExtensionMarks<X> = TypesOf<X>["marks"];
134
+ /**
135
+ * The commands contributed by an extension.
136
+ *
137
+ * @since 0.1.0
138
+ * @category type-level
139
+ */
140
+ export type ExtensionCommands<X> = TypesOf<X>["commands"];
141
+ /**
142
+ * Creates a command from its arguments.
143
+ *
144
+ * @since 0.1.0
145
+ * @category models
146
+ */
147
+ export type CommandCreator = (...args: any) => Command<any, any, any>;
148
+ /**
149
+ * @since 0.1.0
150
+ * @category models
151
+ */
152
+ export interface CommandCreators {
153
+ readonly [name: string]: CommandCreator;
154
+ }
155
+ /**
156
+ * A plugin, a list of plugins, or a function creating them from the
157
+ * editor's schema.
158
+ *
159
+ * @since 0.1.0
160
+ * @category models
161
+ */
162
+ export type PluginInput = AnyPlugin | ReadonlyArray<AnyPlugin> | ((schema: AnySchema) => AnyPlugin | ReadonlyArray<AnyPlugin>);
163
+ /**
164
+ * The contents of a single extension, as given to `defineExtension`.
165
+ *
166
+ * @since 0.1.0
167
+ * @category models
168
+ */
169
+ export interface ExtensionSpec {
170
+ readonly nodes?: NodeSpecs | undefined;
171
+ readonly marks?: MarkSpecs | undefined;
172
+ readonly plugins?: ReadonlyArray<PluginInput> | undefined;
173
+ readonly keymap?: Bindings | undefined;
174
+ readonly commands?: CommandCreators | undefined;
175
+ }
176
+ /**
177
+ * @since 0.1.0
178
+ * @category symbols
179
+ */
180
+ export declare const ExtensionTypeId: unique symbol;
181
+ /**
182
+ * @since 0.1.0
183
+ * @category symbols
184
+ */
185
+ export type ExtensionTypeId = typeof ExtensionTypeId;
186
+ /**
187
+ * An extension: a tree of facets (node and mark specs, plugins,
188
+ * keymaps and commands), each with an optional priority. `T` records,
189
+ * at the type level, what the extension contributes. Extensions are
190
+ * immutable values; combine them with `union` and turn them into an
191
+ * editor with `createEditor`.
192
+ *
193
+ * @since 0.1.0
194
+ * @category models
195
+ */
196
+ export declare class Extension<out T extends ExtensionTypes = EmptyTypes> {
197
+ /** @internal */
198
+ readonly spec: ExtensionSpec | undefined;
199
+ /** @internal */
200
+ readonly children: ReadonlyArray<AnyExtension>;
201
+ /** @internal */
202
+ readonly priority: Priority | undefined;
203
+ readonly [ExtensionTypeId]: {
204
+ readonly _T: (_: never) => T;
205
+ };
206
+ /** @internal */
207
+ constructor(
208
+ /** @internal */
209
+ spec: ExtensionSpec | undefined,
210
+ /** @internal */
211
+ children: ReadonlyArray<AnyExtension>,
212
+ /** @internal */
213
+ priority: Priority | undefined);
214
+ }
215
+ /**
216
+ * Any extension.
217
+ *
218
+ * @since 0.1.0
219
+ * @category models
220
+ */
221
+ export type AnyExtension = Extension<any>;
222
+ /**
223
+ * Whether a value is an `Extension`.
224
+ *
225
+ * @since 0.1.0
226
+ * @category guards
227
+ */
228
+ export declare const isExtension: (u: unknown) => u is AnyExtension;
229
+ type PluginInputE<P> = P extends ((...args: any) => infer X) ? PluginInputE<X> : P extends ReadonlyArray<infer X> ? PluginInputE<X> : P extends Plugin<any, any, infer E, any> ? E : never;
230
+ type PluginInputR<P> = P extends ((...args: any) => infer X) ? PluginInputR<X> : P extends ReadonlyArray<infer X> ? PluginInputR<X> : P extends Plugin<any, any, any, infer R> ? R : never;
231
+ type CreatorE<C> = C extends ((...args: any) => (...args: any) => Effect.Effect<any, infer E, any>) ? E : never;
232
+ type CreatorR<C> = C extends ((...args: any) => (...args: any) => Effect.Effect<any, any, infer R>) ? R : never;
233
+ /**
234
+ * The command types of a set of command creators: their argument
235
+ * tuples.
236
+ *
237
+ * @since 0.1.0
238
+ * @category type-level
239
+ */
240
+ export type CommandArgsOf<C extends CommandCreators> = { readonly [K in keyof C]: Parameters<C[K]>; };
241
+ /**
242
+ * The errors of a set of command creators' commands.
243
+ *
244
+ * @since 0.1.0
245
+ * @category type-level
246
+ */
247
+ export type CommandsError<C extends CommandCreators> = { [K in keyof C]: CreatorE<C[K]>; }[keyof C];
248
+ /**
249
+ * The requirements of a set of command creators' commands.
250
+ *
251
+ * @since 0.1.0
252
+ * @category type-level
253
+ */
254
+ export type CommandsRequirements<C extends CommandCreators> = { [K in keyof C]: CreatorR<C[K]>; }[keyof C];
255
+ /**
256
+ * The extension types described by an `ExtensionSpec`.
257
+ *
258
+ * @since 0.1.0
259
+ * @category type-level
260
+ */
261
+ export interface SpecTypes<N extends NodeSpecs, M extends MarkSpecs, P extends ReadonlyArray<PluginInput>, B extends Bindings, C extends CommandCreators> {
262
+ readonly nodes: N;
263
+ readonly marks: M;
264
+ readonly commands: CommandArgsOf<C>;
265
+ readonly E: PluginInputE<P[number]> | BindingsError<B> | CommandsError<C>;
266
+ readonly R: PluginInputR<P[number]> | BindingsRequirements<B> | CommandsRequirements<C>;
267
+ }
268
+ /**
269
+ * Define an extension from node and mark specs, plugins, a keymap and
270
+ * commands. Every field is optional; the types of all of them are
271
+ * recorded in the extension's type.
272
+ *
273
+ * ```ts skip-type-checking
274
+ * const bold = defineExtension({
275
+ * marks: { strong: { parseDOM: [{ tag: "strong" }], toDOM: () => ["strong", 0] } },
276
+ * commands: { toggleBold: () => (state, dispatch) => toggleMark(state.schema.marks.strong!)(state, dispatch) },
277
+ * keymap: { "Mod-b": (state, dispatch) => toggleMark(state.schema.marks.strong!)(state, dispatch) }
278
+ * })
279
+ * ```
280
+ *
281
+ * Throws a `KeymapError` when a key name in `keymap` is invalid.
282
+ *
283
+ * @since 0.1.0
284
+ * @category constructors
285
+ */
286
+ export declare const defineExtension: <const N extends NodeSpecs = {}, const M extends MarkSpecs = {}, const P extends ReadonlyArray<PluginInput> = readonly [], const B extends Bindings = {}, const C extends CommandCreators = {}>(spec: {
287
+ readonly nodes?: N | undefined;
288
+ readonly marks?: M | undefined;
289
+ readonly plugins?: P | undefined;
290
+ readonly keymap?: B | undefined;
291
+ readonly commands?: C | undefined;
292
+ }) => Extension<SpecTypes<N, M, P, B, C>>;
293
+ /**
294
+ * Merge extensions. The result contributes everything its parts
295
+ * contribute: node, mark and command types are intersected, `E` and `R`
296
+ * are unions. At runtime facets are ordered by priority, then by
297
+ * declaration order (depth first); including the same extension value
298
+ * more than once only uses its first occurrence.
299
+ *
300
+ * @since 0.1.0
301
+ * @category combinators
302
+ */
303
+ export declare const union: <const Exts extends ReadonlyArray<AnyExtension>>(...extensions: Exts) => Extension<MergeTypes<TypesOf<Exts[number]>>>;
304
+ /**
305
+ * Give an extension (and every part of it that doesn't set its own
306
+ * priority) a priority.
307
+ *
308
+ * @since 0.1.0
309
+ * @category combinators
310
+ */
311
+ export declare const withPriority: <T extends ExtensionTypes>(extension: Extension<T>, priority: Priority) => Extension<T>;
312
+ /**
313
+ * Define an extension adding a single node spec.
314
+ *
315
+ * @since 0.1.0
316
+ * @category constructors
317
+ */
318
+ export declare const defineNodeSpec: <const Name extends string, const Spec extends NodeSpec>(name: Name, spec: Spec) => Extension<SpecTypes<{ readonly [K in Name]: Spec; }, {}, readonly [], {}, {}>>;
319
+ /**
320
+ * Define an extension adding a single mark spec.
321
+ *
322
+ * @since 0.1.0
323
+ * @category constructors
324
+ */
325
+ export declare const defineMarkSpec: <const Name extends string, const Spec extends MarkSpec>(name: Name, spec: Spec) => Extension<SpecTypes<{}, { readonly [K in Name]: Spec; }, readonly [], {}, {}>>;
326
+ /**
327
+ * Define an extension adding plugins: a plugin, an array of plugins, or
328
+ * a function creating them from the editor's schema.
329
+ *
330
+ * @since 0.1.0
331
+ * @category constructors
332
+ */
333
+ export declare const definePlugin: <const P extends PluginInput>(plugin: P) => Extension<SpecTypes<{}, {}, readonly [P], {}, {}>>;
334
+ /**
335
+ * Define an extension adding a keymap (see `keymap`). Throws a
336
+ * `KeymapError` when a key name is invalid or bound twice.
337
+ *
338
+ * @since 0.1.0
339
+ * @category constructors
340
+ */
341
+ export declare const defineKeymap: <const B extends Bindings>(bindings: B) => Extension<SpecTypes<{}, {}, readonly [], B, {}>>;
342
+ /**
343
+ * Define an extension adding commands. Each command is given as a
344
+ * function from the command's arguments to a `Command`; the argument
345
+ * types become part of the editor's `commands`, `can()` and `chain()`
346
+ * APIs.
347
+ *
348
+ * ```ts skip-type-checking
349
+ * const ext = defineCommands({
350
+ * insertHello: (times: number) => (state, dispatch) => ...
351
+ * })
352
+ * ```
353
+ *
354
+ * For commands whose argument types depend on the final schema, declare
355
+ * a `CommandSignature` and cast the extension (see `CommandsExtension`).
356
+ *
357
+ * @since 0.1.0
358
+ * @category constructors
359
+ */
360
+ export declare const defineCommands: <const C extends CommandCreators>(commands: C) => Extension<SpecTypes<{}, {}, readonly [], {}, C>>;
361
+ /**
362
+ * The type of an extension that only contributes commands, described
363
+ * by command types (argument tuples or `CommandSignature`s).
364
+ *
365
+ * @since 0.1.0
366
+ * @category type-level
367
+ */
368
+ export type CommandsExtension<C extends CommandTypes, E = never, R = never> = Extension<{
369
+ readonly nodes: {};
370
+ readonly marks: {};
371
+ readonly commands: C;
372
+ readonly E: E;
373
+ readonly R: R;
374
+ }>;
375
+ export {};