@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,409 @@
|
|
|
1
|
+
import { Decoration as Decoration$1, DecorationGroup as DecorationGroup$1, DecorationSet as DecorationSet$1 } from "../view/decoration.js";
|
|
2
|
+
import { EditorView as EditorView$1, __endComposition as __endComposition$1, __parseFromClipboard as __parseFromClipboard$1 } from "../view/view.js";
|
|
3
|
+
import { CORE, adopt, guard, link, registerWrapper, unwrap, unwrapArray, wrap, wrapArray } from "./internal/core.js";
|
|
4
|
+
import { propsToCore } from "./internal/props.js";
|
|
5
|
+
import * as Option from "effect/Option";
|
|
6
|
+
// src/compat/view.ts
|
|
7
|
+
/**
|
|
8
|
+
* A `prosemirror-view`-compatible facade over `@thomasfosterau/effect-richtext/view`.
|
|
9
|
+
*
|
|
10
|
+
* `new EditorView(place, props)` creates a core view with
|
|
11
|
+
* `EditorView.makeUnsafe`, translating the ProseMirror-style props
|
|
12
|
+
* (which receive and return facades) into core props. Decorations wrap
|
|
13
|
+
* core decorations.
|
|
14
|
+
*
|
|
15
|
+
* Ported API surface from prosemirror-view (MIT, Marijn Haverbeke and others).
|
|
16
|
+
*
|
|
17
|
+
* @since 0.1.0
|
|
18
|
+
*/
|
|
19
|
+
const ORIGINAL = Symbol.for("effect-richtext/compat/original");
|
|
20
|
+
const widgetConstructors = /* @__PURE__ */ new WeakMap();
|
|
21
|
+
const widgetToCore = (toDOM) => {
|
|
22
|
+
if (typeof toDOM !== "function") return toDOM;
|
|
23
|
+
let found = widgetConstructors.get(toDOM);
|
|
24
|
+
if (!found) {
|
|
25
|
+
found = (view, getPos) => toDOM(wrap(view), getPos);
|
|
26
|
+
widgetConstructors.set(toDOM, found);
|
|
27
|
+
}
|
|
28
|
+
return found;
|
|
29
|
+
};
|
|
30
|
+
const specToCore = (spec) => {
|
|
31
|
+
if (!spec || !spec.marks) return spec;
|
|
32
|
+
return {
|
|
33
|
+
...spec,
|
|
34
|
+
marks: unwrapArray(spec.marks),
|
|
35
|
+
[ORIGINAL]: spec
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
const originalSpec = (spec) => spec && (spec[ORIGINAL] ?? spec);
|
|
39
|
+
/**
|
|
40
|
+
* Decoration objects can be provided to the view through the
|
|
41
|
+
* `decorations` prop.
|
|
42
|
+
*
|
|
43
|
+
* @since 0.1.0
|
|
44
|
+
* @category models
|
|
45
|
+
*/
|
|
46
|
+
var Decoration = class {
|
|
47
|
+
/** The start position of the decoration. */
|
|
48
|
+
get from() {
|
|
49
|
+
return this[CORE].from;
|
|
50
|
+
}
|
|
51
|
+
/** The end position. Will be the same as `from` for widget decorations. */
|
|
52
|
+
get to() {
|
|
53
|
+
return this[CORE].to;
|
|
54
|
+
}
|
|
55
|
+
/** @internal */
|
|
56
|
+
get type() {
|
|
57
|
+
return this[CORE].type;
|
|
58
|
+
}
|
|
59
|
+
/** The spec provided when creating this decoration. */
|
|
60
|
+
get spec() {
|
|
61
|
+
return originalSpec(this[CORE].spec);
|
|
62
|
+
}
|
|
63
|
+
/** @internal */
|
|
64
|
+
get inline() {
|
|
65
|
+
return this[CORE].inline;
|
|
66
|
+
}
|
|
67
|
+
/** @internal */
|
|
68
|
+
get widget() {
|
|
69
|
+
return this[CORE].widget;
|
|
70
|
+
}
|
|
71
|
+
/** @internal */
|
|
72
|
+
eq(other, offset = 0) {
|
|
73
|
+
return this[CORE].eq(other[CORE], offset);
|
|
74
|
+
}
|
|
75
|
+
/** Creates a widget decoration, which is a DOM node that's shown in the document at the given position. */
|
|
76
|
+
static widget(pos, toDOM, spec) {
|
|
77
|
+
return wrap(Decoration$1.widget(pos, widgetToCore(toDOM), specToCore(spec)));
|
|
78
|
+
}
|
|
79
|
+
/** Creates an inline decoration, which adds the given attributes to each inline node between `from` and `to`. */
|
|
80
|
+
static inline(from, to, attrs, spec) {
|
|
81
|
+
return wrap(Decoration$1.inline(from, to, attrs, spec));
|
|
82
|
+
}
|
|
83
|
+
/** Creates a node decoration. */
|
|
84
|
+
static node(from, to, attrs, spec) {
|
|
85
|
+
return wrap(Decoration$1.node(from, to, attrs, spec));
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
registerWrapper(Decoration$1, (core) => adopt(Decoration.prototype, core));
|
|
89
|
+
/**
|
|
90
|
+
* A collection of decorations, organized in such a way that the
|
|
91
|
+
* drawing algorithm can efficiently use and compare them.
|
|
92
|
+
*
|
|
93
|
+
* @since 0.1.0
|
|
94
|
+
* @category models
|
|
95
|
+
*/
|
|
96
|
+
var DecorationSet = class {
|
|
97
|
+
/** Create a set of decorations, using the structure of the given document. */
|
|
98
|
+
static create(doc, decorations) {
|
|
99
|
+
return wrap(DecorationSet$1.create(doc[CORE], decorations.map(unwrap)));
|
|
100
|
+
}
|
|
101
|
+
/** Find all decorations in this set which touch the given range (including decorations that start or end directly at the boundaries) and match the given predicate on their spec. */
|
|
102
|
+
find(start, end, predicate) {
|
|
103
|
+
return this[CORE].find(start, end, predicate && ((spec) => predicate(originalSpec(spec)))).map(wrap);
|
|
104
|
+
}
|
|
105
|
+
/** Map the set of decorations in response to a change in the document. */
|
|
106
|
+
map(mapping, doc, options) {
|
|
107
|
+
const onRemove = options && options.onRemove;
|
|
108
|
+
return wrap(this[CORE].map(unwrap(mapping), doc[CORE], onRemove && { onRemove: (spec) => onRemove(originalSpec(spec)) }));
|
|
109
|
+
}
|
|
110
|
+
/** Add the given array of decorations to the ones in the set, producing a new set. */
|
|
111
|
+
add(doc, decorations) {
|
|
112
|
+
return wrap(this[CORE].add(doc[CORE], decorations.map(unwrap)));
|
|
113
|
+
}
|
|
114
|
+
/** Create a new set that contains the decorations in this set, minus the ones in the given array. */
|
|
115
|
+
remove(decorations) {
|
|
116
|
+
return wrap(this[CORE].remove(decorations.map(unwrap)));
|
|
117
|
+
}
|
|
118
|
+
/** @internal */
|
|
119
|
+
forChild(offset, node) {
|
|
120
|
+
return wrap(this[CORE].forChild(offset, node[CORE]));
|
|
121
|
+
}
|
|
122
|
+
/** @internal */
|
|
123
|
+
eq(other) {
|
|
124
|
+
return this[CORE].eq(unwrap(other));
|
|
125
|
+
}
|
|
126
|
+
/** @internal */
|
|
127
|
+
locals(node) {
|
|
128
|
+
return wrapArray(this[CORE].locals(node[CORE]));
|
|
129
|
+
}
|
|
130
|
+
/** @internal */
|
|
131
|
+
forEachSet(f) {
|
|
132
|
+
this[CORE].forEachSet((set) => f(wrap(set)));
|
|
133
|
+
}
|
|
134
|
+
/** @internal */
|
|
135
|
+
get local() {
|
|
136
|
+
return wrapArray(this[CORE].local);
|
|
137
|
+
}
|
|
138
|
+
/** @internal */
|
|
139
|
+
get children() {
|
|
140
|
+
return this[CORE].children.map(wrap);
|
|
141
|
+
}
|
|
142
|
+
/** @internal */
|
|
143
|
+
static removeOverlap(spans) {
|
|
144
|
+
const core = unwrapArray(spans);
|
|
145
|
+
const result = DecorationSet$1.removeOverlap(core);
|
|
146
|
+
return result === core ? spans : result.map(wrap);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
registerWrapper(DecorationSet$1, (core) => adopt(DecorationSet.prototype, core));
|
|
150
|
+
DecorationSet.empty = wrap(DecorationSet$1.empty);
|
|
151
|
+
/** A facade for the core's (non-exported) group of decoration sources. @internal */
|
|
152
|
+
var DecorationGroup = class {
|
|
153
|
+
map(mapping, doc) {
|
|
154
|
+
return wrap(this[CORE].map(unwrap(mapping), doc[CORE]));
|
|
155
|
+
}
|
|
156
|
+
forChild(offset, child) {
|
|
157
|
+
return wrap(this[CORE].forChild(offset, child[CORE]));
|
|
158
|
+
}
|
|
159
|
+
eq(other) {
|
|
160
|
+
return this[CORE].eq(unwrap(other));
|
|
161
|
+
}
|
|
162
|
+
forEachSet(f) {
|
|
163
|
+
this[CORE].forEachSet((set) => f(wrap(set)));
|
|
164
|
+
}
|
|
165
|
+
locals(node) {
|
|
166
|
+
return wrapArray(this[CORE].locals(node[CORE]));
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
registerWrapper(DecorationGroup$1, (core) => adopt(DecorationGroup.prototype, core));
|
|
170
|
+
const constructing = [];
|
|
171
|
+
/**
|
|
172
|
+
* An editor view manages the DOM structure that represents an editable
|
|
173
|
+
* document.
|
|
174
|
+
*
|
|
175
|
+
* @since 0.1.0
|
|
176
|
+
* @category models
|
|
177
|
+
*/
|
|
178
|
+
var EditorView = class {
|
|
179
|
+
/** Create a view. */
|
|
180
|
+
constructor(place, props) {
|
|
181
|
+
this._props = props;
|
|
182
|
+
this.propsCache = /* @__PURE__ */ new WeakMap();
|
|
183
|
+
this.dispatch = this.dispatch.bind(this);
|
|
184
|
+
constructing.push(this);
|
|
185
|
+
try {
|
|
186
|
+
const core = guard(() => EditorView$1.makeUnsafe(place, this.propsToCore(props)));
|
|
187
|
+
link(this, core);
|
|
188
|
+
} finally {
|
|
189
|
+
constructing.pop();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
propsToCore(props) {
|
|
193
|
+
return propsToCore(props, this, this.propsCache);
|
|
194
|
+
}
|
|
195
|
+
/** The view's current state. */
|
|
196
|
+
get state() {
|
|
197
|
+
return wrap(this[CORE].state);
|
|
198
|
+
}
|
|
199
|
+
/** An editable DOM node containing the document. */
|
|
200
|
+
get dom() {
|
|
201
|
+
return this[CORE].dom;
|
|
202
|
+
}
|
|
203
|
+
/** Indicates whether the editor is currently editable. */
|
|
204
|
+
get editable() {
|
|
205
|
+
return this[CORE].editable;
|
|
206
|
+
}
|
|
207
|
+
/** When editor content is being dragged, this object contains information about the dragged slice and whether it is being copied or moved. */
|
|
208
|
+
get dragging() {
|
|
209
|
+
const dragging = this[CORE].dragging;
|
|
210
|
+
return dragging && {
|
|
211
|
+
slice: wrap(dragging.slice),
|
|
212
|
+
move: dragging.move
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
set dragging(value) {
|
|
216
|
+
this[CORE].dragging = value && {
|
|
217
|
+
slice: value.slice[CORE],
|
|
218
|
+
move: value.move
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
/** Holds `true` when a composition is active. */
|
|
222
|
+
get composing() {
|
|
223
|
+
return this[CORE].composing;
|
|
224
|
+
}
|
|
225
|
+
/** The view's current props. */
|
|
226
|
+
get props() {
|
|
227
|
+
if (this._props.state != this.state) {
|
|
228
|
+
const prev = this._props;
|
|
229
|
+
this._props = {};
|
|
230
|
+
for (const name in prev) this._props[name] = prev[name];
|
|
231
|
+
this._props.state = this.state;
|
|
232
|
+
}
|
|
233
|
+
return this._props;
|
|
234
|
+
}
|
|
235
|
+
/** Update the view's props. Will immediately cause an update to the DOM. */
|
|
236
|
+
update(props) {
|
|
237
|
+
this._props = props;
|
|
238
|
+
guard(() => this[CORE].update(this.propsToCore(props)));
|
|
239
|
+
}
|
|
240
|
+
/** Update the view by updating existing props object with the object given as argument. */
|
|
241
|
+
setProps(props) {
|
|
242
|
+
const updated = {};
|
|
243
|
+
for (const name in this._props) updated[name] = this._props[name];
|
|
244
|
+
updated.state = this.state;
|
|
245
|
+
for (const name in props) updated[name] = props[name];
|
|
246
|
+
this.update(updated);
|
|
247
|
+
}
|
|
248
|
+
/** Update the editor's `state` prop, without touching any of the other props. */
|
|
249
|
+
updateState(state) {
|
|
250
|
+
guard(() => this[CORE].updateState(state[CORE]));
|
|
251
|
+
}
|
|
252
|
+
someProp(propName, f) {
|
|
253
|
+
const prop = this._props && this._props[propName];
|
|
254
|
+
let value;
|
|
255
|
+
if (prop != null && (value = f ? f(prop) : prop)) return value;
|
|
256
|
+
const direct = this._props.plugins || [];
|
|
257
|
+
for (let i = 0; i < direct.length; i++) {
|
|
258
|
+
const prop = direct[i].props[propName];
|
|
259
|
+
if (prop != null && (value = f ? f(prop) : prop)) return value;
|
|
260
|
+
}
|
|
261
|
+
const plugins = this.state.plugins;
|
|
262
|
+
if (plugins) for (let i = 0; i < plugins.length; i++) {
|
|
263
|
+
const prop = plugins[i].props[propName];
|
|
264
|
+
if (prop != null && (value = f ? f(prop) : prop)) return value;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/** Query whether the view has focus. */
|
|
268
|
+
hasFocus() {
|
|
269
|
+
return this[CORE].hasFocus();
|
|
270
|
+
}
|
|
271
|
+
/** Focus the editor. */
|
|
272
|
+
focus() {
|
|
273
|
+
this[CORE].focus();
|
|
274
|
+
}
|
|
275
|
+
/** Get the document root in which the editor exists. */
|
|
276
|
+
get root() {
|
|
277
|
+
return this[CORE].root;
|
|
278
|
+
}
|
|
279
|
+
/** When an existing editor view is moved to a new document or shadow tree, call this to make it recompute its root. */
|
|
280
|
+
updateRoot() {
|
|
281
|
+
this[CORE].updateRoot();
|
|
282
|
+
}
|
|
283
|
+
/** Given a pair of viewport coordinates, return the document position that corresponds to them. */
|
|
284
|
+
posAtCoords(coords) {
|
|
285
|
+
return Option.getOrNull(this[CORE].posAtCoords(coords));
|
|
286
|
+
}
|
|
287
|
+
/** Returns the viewport rectangle at a given document position. */
|
|
288
|
+
coordsAtPos(pos, side = 1) {
|
|
289
|
+
return guard(() => this[CORE].coordsAtPos(pos, side));
|
|
290
|
+
}
|
|
291
|
+
/** Find the DOM position that corresponds to the given document position. */
|
|
292
|
+
domAtPos(pos, side = 0) {
|
|
293
|
+
return guard(() => this[CORE].domAtPos(pos, side));
|
|
294
|
+
}
|
|
295
|
+
/** Find the DOM node that represents the document node after the given position. */
|
|
296
|
+
nodeDOM(pos) {
|
|
297
|
+
return Option.getOrNull(this[CORE].nodeDOM(pos));
|
|
298
|
+
}
|
|
299
|
+
/** Find the document position that corresponds to a given DOM position. */
|
|
300
|
+
posAtDOM(node, offset, bias = -1) {
|
|
301
|
+
return guard(() => this[CORE].posAtDOMUnsafe(node, offset, bias));
|
|
302
|
+
}
|
|
303
|
+
/** Find out whether the selection is at the end of a textblock when moving in a given direction. */
|
|
304
|
+
endOfTextblock(dir, state) {
|
|
305
|
+
return this[CORE].endOfTextblock(dir, state && state[CORE]);
|
|
306
|
+
}
|
|
307
|
+
/** Run the editor's paste logic with the given HTML string. */
|
|
308
|
+
pasteHTML(html, event) {
|
|
309
|
+
return guard(() => this[CORE].pasteHTML(html, event));
|
|
310
|
+
}
|
|
311
|
+
/** Run the editor's paste logic with the given plain-text input. */
|
|
312
|
+
pasteText(text, event) {
|
|
313
|
+
return guard(() => this[CORE].pasteText(text, event));
|
|
314
|
+
}
|
|
315
|
+
/** Serialize the given slice as it would be if it was copied from this editor. */
|
|
316
|
+
serializeForClipboard(slice) {
|
|
317
|
+
const result = guard(() => this[CORE].serializeForClipboard(slice[CORE]));
|
|
318
|
+
return {
|
|
319
|
+
dom: result.dom,
|
|
320
|
+
text: result.text,
|
|
321
|
+
slice: wrap(result.slice)
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
/** Removes the editor from the DOM and destroys all node views. */
|
|
325
|
+
destroy() {
|
|
326
|
+
this[CORE].destroy();
|
|
327
|
+
}
|
|
328
|
+
/** This is true when the view has been destroyed (and thus should not be used anymore). */
|
|
329
|
+
get isDestroyed() {
|
|
330
|
+
return this[CORE].isDestroyed;
|
|
331
|
+
}
|
|
332
|
+
/** Used for testing. */
|
|
333
|
+
dispatchEvent(event) {
|
|
334
|
+
this[CORE].dispatchEvent(event);
|
|
335
|
+
}
|
|
336
|
+
/** Dispatch a transaction. */
|
|
337
|
+
dispatch(tr) {
|
|
338
|
+
guard(() => this[CORE].dispatchUnsafe(tr[CORE]));
|
|
339
|
+
}
|
|
340
|
+
/** @internal */
|
|
341
|
+
domSelectionRange() {
|
|
342
|
+
return this[CORE].domSelectionRange();
|
|
343
|
+
}
|
|
344
|
+
/** @internal */
|
|
345
|
+
domSelection() {
|
|
346
|
+
return this[CORE].domSelection();
|
|
347
|
+
}
|
|
348
|
+
/** @internal */
|
|
349
|
+
scrollToSelection() {
|
|
350
|
+
this[CORE].scrollToSelection();
|
|
351
|
+
}
|
|
352
|
+
/** @internal */
|
|
353
|
+
get domObserver() {
|
|
354
|
+
return this[CORE].domObserver;
|
|
355
|
+
}
|
|
356
|
+
/** @internal */
|
|
357
|
+
get docView() {
|
|
358
|
+
return this[CORE].docView;
|
|
359
|
+
}
|
|
360
|
+
/** @internal */
|
|
361
|
+
get input() {
|
|
362
|
+
return this[CORE].input;
|
|
363
|
+
}
|
|
364
|
+
/** @internal */
|
|
365
|
+
get focused() {
|
|
366
|
+
return this[CORE].focused;
|
|
367
|
+
}
|
|
368
|
+
/** @internal */
|
|
369
|
+
get markCursor() {
|
|
370
|
+
const marks = this[CORE].markCursor;
|
|
371
|
+
return marks && wrapArray(marks);
|
|
372
|
+
}
|
|
373
|
+
/** @internal */
|
|
374
|
+
get cursorWrapper() {
|
|
375
|
+
return this[CORE].cursorWrapper;
|
|
376
|
+
}
|
|
377
|
+
/** @internal */
|
|
378
|
+
get lastSelectedViewDesc() {
|
|
379
|
+
return this[CORE].lastSelectedViewDesc;
|
|
380
|
+
}
|
|
381
|
+
/** @internal */
|
|
382
|
+
get trackWrites() {
|
|
383
|
+
return this[CORE].trackWrites;
|
|
384
|
+
}
|
|
385
|
+
/** @internal */
|
|
386
|
+
get nodeViews() {
|
|
387
|
+
return this[CORE].nodeViews;
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
registerWrapper(EditorView$1, (core) => {
|
|
391
|
+
const facade = constructing.at(-1);
|
|
392
|
+
if (facade && !(CORE in facade)) return facade;
|
|
393
|
+
const view = adopt(EditorView.prototype, core);
|
|
394
|
+
view._props = core.props;
|
|
395
|
+
view.propsCache = /* @__PURE__ */ new WeakMap();
|
|
396
|
+
view.dispatch = view.dispatch.bind(view);
|
|
397
|
+
return view;
|
|
398
|
+
});
|
|
399
|
+
/** @internal */
|
|
400
|
+
const __parseFromClipboard = (view, text, html, plainText, $context) => wrap(__parseFromClipboard$1(view[CORE], text, html, plainText, $context[CORE]));
|
|
401
|
+
/** @internal */
|
|
402
|
+
const __endComposition = (view, restarting = false) => __endComposition$1(view[CORE], restarting);
|
|
403
|
+
function toCore(value) {
|
|
404
|
+
return unwrap(value);
|
|
405
|
+
}
|
|
406
|
+
function fromCore(value) {
|
|
407
|
+
return wrap(value);
|
|
408
|
+
}
|
|
409
|
+
export { Decoration, DecorationSet, EditorView, __endComposition, __parseFromClipboard, fromCore, toCore };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { EditorView, PosAtCoords } from "./view/view.js";
|
|
2
|
+
import { Plugin } from "./state/plugin.js";
|
|
3
|
+
import "./state.js";
|
|
4
|
+
import "./view.js";
|
|
5
|
+
/**
|
|
6
|
+
* Options for `dropCursor`.
|
|
7
|
+
*
|
|
8
|
+
* @since 0.1.0
|
|
9
|
+
* @category models
|
|
10
|
+
*/
|
|
11
|
+
export interface DropCursorOptions {
|
|
12
|
+
/**
|
|
13
|
+
* The color of the cursor. Defaults to `black`. Use `false` to apply
|
|
14
|
+
* no color and rely only on class.
|
|
15
|
+
*/
|
|
16
|
+
readonly color?: string | false | undefined;
|
|
17
|
+
/** The precise width of the cursor in pixels. Defaults to 1. */
|
|
18
|
+
readonly width?: number | undefined;
|
|
19
|
+
/** A CSS class name to add to the cursor element. */
|
|
20
|
+
readonly class?: string | undefined;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The type of the `disableDropCursor` property node specs may define to
|
|
24
|
+
* control the showing of a drop cursor inside them.
|
|
25
|
+
*
|
|
26
|
+
* @since 0.1.0
|
|
27
|
+
* @category models
|
|
28
|
+
*/
|
|
29
|
+
export type DisableDropCursor = boolean | ((view: EditorView<any, any, any>, pos: PosAtCoords, event: DragEvent) => boolean);
|
|
30
|
+
/**
|
|
31
|
+
* Create a plugin that, when added to an editor, causes a decoration to
|
|
32
|
+
* show up at the drop position when something is dragged over the
|
|
33
|
+
* editor.
|
|
34
|
+
*
|
|
35
|
+
* Nodes may add a `disableDropCursor` property (see `DisableDropCursor`)
|
|
36
|
+
* to their spec to control the showing of a drop cursor inside them.
|
|
37
|
+
* This may be a boolean or a function, which will be called with a view
|
|
38
|
+
* and a position, and should return a boolean.
|
|
39
|
+
*
|
|
40
|
+
* The cursor element gets the class `prosemirror-dropcursor-block` or
|
|
41
|
+
* `prosemirror-dropcursor-inline`, depending on the position.
|
|
42
|
+
*
|
|
43
|
+
* @since 0.1.0
|
|
44
|
+
* @category constructors
|
|
45
|
+
*/
|
|
46
|
+
export declare const dropCursor: (options?: DropCursorOptions) => Plugin<undefined>;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { Plugin } from "./state/plugin.js";
|
|
2
|
+
import { dropPoint } from "./transform/structure.js";
|
|
3
|
+
import * as Option from "effect/Option";
|
|
4
|
+
import * as Predicate from "effect/Predicate";
|
|
5
|
+
// src/dropcursor.ts
|
|
6
|
+
/**
|
|
7
|
+
* A plugin that shows a drop cursor (a line at the drop position) when
|
|
8
|
+
* something is dragged over the editor. Ported from
|
|
9
|
+
* `prosemirror-dropcursor`.
|
|
10
|
+
*
|
|
11
|
+
* @since 0.1.0
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Create a plugin that, when added to an editor, causes a decoration to
|
|
15
|
+
* show up at the drop position when something is dragged over the
|
|
16
|
+
* editor.
|
|
17
|
+
*
|
|
18
|
+
* Nodes may add a `disableDropCursor` property (see `DisableDropCursor`)
|
|
19
|
+
* to their spec to control the showing of a drop cursor inside them.
|
|
20
|
+
* This may be a boolean or a function, which will be called with a view
|
|
21
|
+
* and a position, and should return a boolean.
|
|
22
|
+
*
|
|
23
|
+
* The cursor element gets the class `prosemirror-dropcursor-block` or
|
|
24
|
+
* `prosemirror-dropcursor-inline`, depending on the position.
|
|
25
|
+
*
|
|
26
|
+
* @since 0.1.0
|
|
27
|
+
* @category constructors
|
|
28
|
+
*/
|
|
29
|
+
const dropCursor = (options = {}) => new Plugin({ view: (editorView) => new DropCursorView(editorView, options) });
|
|
30
|
+
const events = [
|
|
31
|
+
"dragover",
|
|
32
|
+
"dragend",
|
|
33
|
+
"drop",
|
|
34
|
+
"dragleave"
|
|
35
|
+
];
|
|
36
|
+
var DropCursorView = class {
|
|
37
|
+
constructor(editorView, options) {
|
|
38
|
+
this.editorView = editorView;
|
|
39
|
+
this.cursorPos = null;
|
|
40
|
+
this.element = null;
|
|
41
|
+
this.timeout = void 0;
|
|
42
|
+
this.width = options.width ?? 1;
|
|
43
|
+
this.color = options.color === false ? void 0 : options.color || "black";
|
|
44
|
+
this.class = options.class;
|
|
45
|
+
this.handlers = events.map((name) => {
|
|
46
|
+
const handler = (e) => {
|
|
47
|
+
this[name](e);
|
|
48
|
+
};
|
|
49
|
+
editorView.dom.addEventListener(name, handler);
|
|
50
|
+
return {
|
|
51
|
+
name,
|
|
52
|
+
handler
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
destroy() {
|
|
57
|
+
this.handlers.forEach(({ handler, name }) => this.editorView.dom.removeEventListener(name, handler));
|
|
58
|
+
clearTimeout(this.timeout);
|
|
59
|
+
if (this.element) {
|
|
60
|
+
this.element.remove();
|
|
61
|
+
this.element = null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
update(editorView, prevState) {
|
|
65
|
+
if (this.cursorPos != null && prevState.doc !== editorView.state.doc) {
|
|
66
|
+
if (this.cursorPos > editorView.state.doc.content.size) this.setCursor(null);
|
|
67
|
+
else this.updateOverlay();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
setCursor(pos) {
|
|
71
|
+
if (pos === this.cursorPos) return;
|
|
72
|
+
this.cursorPos = pos;
|
|
73
|
+
if (pos == null) {
|
|
74
|
+
this.element?.remove();
|
|
75
|
+
this.element = null;
|
|
76
|
+
} else this.updateOverlay();
|
|
77
|
+
}
|
|
78
|
+
updateOverlay() {
|
|
79
|
+
const view = this.editorView;
|
|
80
|
+
const $pos = view.state.doc.resolveUnsafe(this.cursorPos);
|
|
81
|
+
const isBlock = !$pos.parent.inlineContent;
|
|
82
|
+
let rect;
|
|
83
|
+
const editorDOM = view.dom, editorRect = editorDOM.getBoundingClientRect();
|
|
84
|
+
const scaleX = editorRect.width / editorDOM.offsetWidth, scaleY = editorRect.height / editorDOM.offsetHeight;
|
|
85
|
+
if (isBlock) {
|
|
86
|
+
const before = $pos.nodeBeforeOrNull, after = $pos.nodeAfterOrNull;
|
|
87
|
+
if (before || after) {
|
|
88
|
+
const node = Option.getOrNull(view.nodeDOM(this.cursorPos - (before ? before.nodeSize : 0)));
|
|
89
|
+
if (node) {
|
|
90
|
+
const nodeRect = node.getBoundingClientRect();
|
|
91
|
+
let top = before ? nodeRect.bottom : nodeRect.top;
|
|
92
|
+
if (before && after) {
|
|
93
|
+
const afterDOM = Option.getOrNull(view.nodeDOM(this.cursorPos));
|
|
94
|
+
if (afterDOM) top = (top + afterDOM.getBoundingClientRect().top) / 2;
|
|
95
|
+
}
|
|
96
|
+
const halfWidth = this.width / 2 * scaleY;
|
|
97
|
+
rect = {
|
|
98
|
+
left: nodeRect.left,
|
|
99
|
+
right: nodeRect.right,
|
|
100
|
+
top: top - halfWidth,
|
|
101
|
+
bottom: top + halfWidth
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (!rect) {
|
|
107
|
+
const coords = view.coordsAtPos(this.cursorPos);
|
|
108
|
+
const halfWidth = this.width / 2 * scaleX;
|
|
109
|
+
rect = {
|
|
110
|
+
left: coords.left - halfWidth,
|
|
111
|
+
right: coords.left + halfWidth,
|
|
112
|
+
top: coords.top,
|
|
113
|
+
bottom: coords.bottom
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
const doc = editorDOM.ownerDocument;
|
|
117
|
+
const parent = editorDOM.offsetParent;
|
|
118
|
+
if (!this.element) {
|
|
119
|
+
this.element = (parent ?? doc.body).appendChild(doc.createElement("div"));
|
|
120
|
+
if (this.class) this.element.className = this.class;
|
|
121
|
+
this.element.style.cssText = "position: absolute; z-index: 50; pointer-events: none;";
|
|
122
|
+
if (this.color) this.element.style.backgroundColor = this.color;
|
|
123
|
+
}
|
|
124
|
+
this.element.classList.toggle("prosemirror-dropcursor-block", isBlock);
|
|
125
|
+
this.element.classList.toggle("prosemirror-dropcursor-inline", !isBlock);
|
|
126
|
+
let parentLeft, parentTop;
|
|
127
|
+
const win = doc.defaultView ?? window;
|
|
128
|
+
if (!parent || parent === doc.body && win.getComputedStyle(parent).position === "static") {
|
|
129
|
+
parentLeft = -win.pageXOffset;
|
|
130
|
+
parentTop = -win.pageYOffset;
|
|
131
|
+
} else {
|
|
132
|
+
const rect = parent.getBoundingClientRect();
|
|
133
|
+
const parentScaleX = rect.width / parent.offsetWidth, parentScaleY = rect.height / parent.offsetHeight;
|
|
134
|
+
parentLeft = rect.left - parent.scrollLeft * parentScaleX;
|
|
135
|
+
parentTop = rect.top - parent.scrollTop * parentScaleY;
|
|
136
|
+
}
|
|
137
|
+
this.element.style.left = (rect.left - parentLeft) / scaleX + "px";
|
|
138
|
+
this.element.style.top = (rect.top - parentTop) / scaleY + "px";
|
|
139
|
+
this.element.style.width = (rect.right - rect.left) / scaleX + "px";
|
|
140
|
+
this.element.style.height = (rect.bottom - rect.top) / scaleY + "px";
|
|
141
|
+
}
|
|
142
|
+
scheduleRemoval(timeout) {
|
|
143
|
+
clearTimeout(this.timeout);
|
|
144
|
+
this.timeout = setTimeout(() => this.setCursor(null), timeout);
|
|
145
|
+
}
|
|
146
|
+
dragover(event) {
|
|
147
|
+
const view = this.editorView;
|
|
148
|
+
if (!view.editable) return;
|
|
149
|
+
const pos = Option.getOrNull(view.posAtCoords({
|
|
150
|
+
left: event.clientX,
|
|
151
|
+
top: event.clientY
|
|
152
|
+
}));
|
|
153
|
+
const node = pos && pos.inside >= 0 ? view.state.doc.nodeAtOrNull(pos.inside) : null;
|
|
154
|
+
const disableDropCursor = node ? node.type.spec.disableDropCursor : void 0;
|
|
155
|
+
const disabled = Predicate.isFunction(disableDropCursor) ? disableDropCursor(view, pos, event) : disableDropCursor;
|
|
156
|
+
if (pos && !disabled) {
|
|
157
|
+
let target = pos.pos;
|
|
158
|
+
if (view.dragging && view.dragging.slice) {
|
|
159
|
+
const point = Option.getOrNull(dropPoint(view.state.doc, target, view.dragging.slice));
|
|
160
|
+
if (point != null) target = point;
|
|
161
|
+
}
|
|
162
|
+
this.setCursor(target);
|
|
163
|
+
this.scheduleRemoval(5e3);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
dragend() {
|
|
167
|
+
this.scheduleRemoval(20);
|
|
168
|
+
}
|
|
169
|
+
drop() {
|
|
170
|
+
this.scheduleRemoval(20);
|
|
171
|
+
}
|
|
172
|
+
dragleave(event) {
|
|
173
|
+
if (!this.editorView.dom.contains(event.relatedTarget)) this.setCursor(null);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
export { dropCursor };
|