edytor 0.1.0-next.17 → 0.1.0-next.18
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/README.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
Edytor aims to be for Svelte what Slate.js is for React: a heavily customizable editor with an API to build any kind of collaborative rich text editor.
|
|
17
17
|
|
|
18
|
-
> **Work in progress.** Edytor is a pre-release (`0.1.0-next.
|
|
18
|
+
> **Work in progress.** Edytor is a pre-release (`0.1.0-next.18`, `edytor@next` on npm) and not ready for production; the API changes between releases without a compatibility layer. The untagged `edytor@0.0.11` on npm predates the current API. Issues and PRs are welcome: when you report a bug, include the document's JSON value.
|
|
19
19
|
|
|
20
20
|
## Features
|
|
21
21
|
|
|
@@ -323,18 +323,13 @@
|
|
|
323
323
|
|
|
324
324
|
const nonNativeEditableBlockChromeSelection = (node: HTMLElement) => {
|
|
325
325
|
const { selection } = edytor;
|
|
326
|
-
const pointerdown = (event: PointerEvent) =>
|
|
327
|
-
selection.handleNonNativeEditableBlockChromePointerDown(event);
|
|
328
|
-
node.addEventListener('pointerdown', pointerdown, true);
|
|
329
326
|
// `selectstart` is the only event fired before a drag-selection
|
|
330
327
|
// begins — the guard keeps one from starting on non-editable
|
|
331
|
-
// chrome (markers, void/island chrome, plugin UI).
|
|
328
|
+
// chrome (markers, void/island chrome, plugin UI). A press on that
|
|
329
|
+
// chrome is the press's (`events/onFocus.ts`).
|
|
332
330
|
node.addEventListener('selectstart', selection.onSelectStart);
|
|
333
331
|
return {
|
|
334
|
-
destroy: () =>
|
|
335
|
-
node.removeEventListener('pointerdown', pointerdown, true);
|
|
336
|
-
node.removeEventListener('selectstart', selection.onSelectStart);
|
|
337
|
-
}
|
|
332
|
+
destroy: () => node.removeEventListener('selectstart', selection.onSelectStart)
|
|
338
333
|
};
|
|
339
334
|
};
|
|
340
335
|
</script>
|
package/dist/events/onFocus.js
CHANGED
|
@@ -39,6 +39,35 @@ export const takeKeys = (edytor) => {
|
|
|
39
39
|
};
|
|
40
40
|
export const attachFocus = (edytor, node) => {
|
|
41
41
|
let lastPointerDownInsideEditorAt = Number.NEGATIVE_INFINITY;
|
|
42
|
+
/*
|
|
43
|
+
* The press: one per primary button press, its `pointerdown`, or a
|
|
44
|
+
* `mousedown` no `pointerdown` came before. WebKit fires no
|
|
45
|
+
* `pointercancel` at a native `dragstart` (a block handle's drag) and,
|
|
46
|
+
* believing the button still down, no `pointerdown` for the next press,
|
|
47
|
+
* only its `mousedown` (WebKit bugs 202287, 222632, 279749): that
|
|
48
|
+
* primary `mousedown` is the press (`lone`). A primary `pointerdown` arms
|
|
49
|
+
* `compat` until the `mousedown` it is followed by (before or after its
|
|
50
|
+
* release, a touch's comes after), so a pair counts once. Only the
|
|
51
|
+
* browser's own `mousedown` stands for a missing press; a script's is none.
|
|
52
|
+
*/
|
|
53
|
+
let compat = false;
|
|
54
|
+
let lone = null;
|
|
55
|
+
/** Where the press landed: the gesture serial, and whether the user went outside. */
|
|
56
|
+
const gesture = (event) => {
|
|
57
|
+
edytor.markUserGesture();
|
|
58
|
+
edytor.lastUserGestureOutsideEditor = Boolean(event.target instanceof Node && !edytor.node?.contains(event.target));
|
|
59
|
+
};
|
|
60
|
+
/** A press inside the host (its bubbling phase: an element inside that took it keeps it). */
|
|
61
|
+
const pressInside = (event) => {
|
|
62
|
+
// A pointer gesture abandons a live composition (D-7).
|
|
63
|
+
edytor.composition.abandon();
|
|
64
|
+
lastPointerDownInsideEditorAt = getEventTimeStamp(event);
|
|
65
|
+
edytor.projector.pressed();
|
|
66
|
+
edytor.selection.clearModelSelectionPreservation();
|
|
67
|
+
edytor.selection.capturePointerDragStart(event);
|
|
68
|
+
edytor.selection.clearInlineBlockSelection();
|
|
69
|
+
edytor.selection.collapseSelectedBlocksAtPointer(event);
|
|
70
|
+
};
|
|
42
71
|
const clearNativeSelectionAfterExternalFocus = () => {
|
|
43
72
|
const activeElement = getActiveElement(node);
|
|
44
73
|
if (activeElement instanceof Node && node.contains(activeElement)) {
|
|
@@ -112,26 +141,37 @@ export const attachFocus = (edytor, node) => {
|
|
|
112
141
|
queueMicrotask(restore);
|
|
113
142
|
};
|
|
114
143
|
return [
|
|
115
|
-
// Any
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
//
|
|
144
|
+
// Any press anywhere disarms pending restores — Firefox can move
|
|
145
|
+
// the DOM selection on outside clicks without blurring the editor,
|
|
146
|
+
// so node-local marking is not enough. The target also records
|
|
147
|
+
// where the gesture landed: an outside press means the current
|
|
148
|
+
// focus/selection is user-owned until an inside gesture or focusin
|
|
149
|
+
// returns it.
|
|
121
150
|
on(node.ownerDocument, 'pointerdown', (event) => {
|
|
122
|
-
|
|
123
|
-
|
|
151
|
+
if (event.isPrimary)
|
|
152
|
+
compat = true;
|
|
153
|
+
lone = null;
|
|
154
|
+
gesture(event);
|
|
155
|
+
}, { capture: true }),
|
|
156
|
+
on(node.ownerDocument, 'mousedown', (event) => {
|
|
157
|
+
lone = compat || !event.isTrusted || event.button !== 0 ? null : event;
|
|
158
|
+
compat = false;
|
|
159
|
+
if (lone)
|
|
160
|
+
gesture(event);
|
|
161
|
+
}, { capture: true }),
|
|
162
|
+
// A press on a block's non-editable chrome places the caret in its text.
|
|
163
|
+
on(node, 'pointerdown', edytor.selection.handleNonNativeEditableBlockChromePointerDown, {
|
|
164
|
+
capture: true
|
|
165
|
+
}),
|
|
166
|
+
on(node, 'mousedown', (event) => {
|
|
167
|
+
if (event === lone)
|
|
168
|
+
edytor.selection.handleNonNativeEditableBlockChromePointerDown(event);
|
|
124
169
|
}, { capture: true }),
|
|
125
170
|
// The document's capture listener already marked the gesture.
|
|
126
|
-
on(node, 'pointerdown',
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
edytor.projector.pressed();
|
|
131
|
-
edytor.selection.clearModelSelectionPreservation();
|
|
132
|
-
edytor.selection.capturePointerDragStart(event);
|
|
133
|
-
edytor.selection.clearInlineBlockSelection();
|
|
134
|
-
edytor.selection.collapseSelectedBlocksAtPointer(event);
|
|
171
|
+
on(node, 'pointerdown', pressInside),
|
|
172
|
+
on(node, 'mousedown', (event) => {
|
|
173
|
+
if (event === lone)
|
|
174
|
+
pressInside(event);
|
|
135
175
|
}),
|
|
136
176
|
on(node, 'pointerup', (event) => {
|
|
137
177
|
edytor.markUserGesture();
|
|
@@ -166,7 +166,7 @@ export declare class EdytorSelection {
|
|
|
166
166
|
private isInsideEditableText;
|
|
167
167
|
private getNonNativeEditableIslandBlock;
|
|
168
168
|
private getNonNativeEditableBlockChromeBlock;
|
|
169
|
-
handleNonNativeEditableBlockChromePointerDown: (event:
|
|
169
|
+
handleNonNativeEditableBlockChromePointerDown: (event: MouseEvent) => void;
|
|
170
170
|
private normalizeTextRangePoints;
|
|
171
171
|
init: () => void;
|
|
172
172
|
/**
|
|
@@ -179,7 +179,7 @@ export declare class EdytorSelection {
|
|
|
179
179
|
private getTextPointFromClientPoint;
|
|
180
180
|
private getTextOffsetFromClientPoint;
|
|
181
181
|
setTextSelectionFromPointer: (text: Text, clientX: number, clientY: number) => void;
|
|
182
|
-
capturePointerDragStart: (event:
|
|
182
|
+
capturePointerDragStart: (event: MouseEvent) => void;
|
|
183
183
|
clearPointerDragStart: () => void;
|
|
184
184
|
/**
|
|
185
185
|
* The block selection value over which the DOM caret was put — a primary
|
|
@@ -191,7 +191,7 @@ export declare class EdytorSelection {
|
|
|
191
191
|
* when the block selection shows no DOM range (for the paste's own keys).
|
|
192
192
|
*/
|
|
193
193
|
placedOver: SelectionValue | null;
|
|
194
|
-
collapseSelectedBlocksAtPointer: (event:
|
|
194
|
+
collapseSelectedBlocksAtPointer: (event: MouseEvent) => void;
|
|
195
195
|
restoreInlineAtomDragRange: (event: PointerEvent) => void;
|
|
196
196
|
/**
|
|
197
197
|
* `selectstart` is the only event fired before a drag-selection begins.
|