@meowdown/core 0.74.1 → 0.74.2
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/dist/index.d.ts +6 -0
- package/dist/index.js +271 -185
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1482,6 +1482,12 @@ interface LinkHoverOptions {
|
|
|
1482
1482
|
* software keyboard.
|
|
1483
1483
|
*/
|
|
1484
1484
|
export declare function defineLinkHoverHandler(onHoverChange: LinkHoverHandler, { canLeave }?: LinkHoverOptions): PlainExtension;
|
|
1485
|
+
/**
|
|
1486
|
+
* Tell the link hover handler that the user dismissed the UI it opened. The
|
|
1487
|
+
* link under the pointer stays silent until the pointer leaves it, so a
|
|
1488
|
+
* pending hover cannot reopen the UI.
|
|
1489
|
+
*/
|
|
1490
|
+
export declare function dismissLinkHover(state: EditorState): void;
|
|
1485
1491
|
//#endregion
|
|
1486
1492
|
//#region src/extensions/link-paste.d.ts
|
|
1487
1493
|
/**
|
package/dist/index.js
CHANGED
|
@@ -84,20 +84,86 @@ function getIsComposing() {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
//#endregion
|
|
87
|
-
//#region src/utils/
|
|
87
|
+
//#region src/utils/input-modality.ts
|
|
88
|
+
const KEYBOARD_MODALITY_KEYS = /* @__PURE__ */ new Set([
|
|
89
|
+
"ArrowLeft",
|
|
90
|
+
"ArrowRight",
|
|
91
|
+
"ArrowUp",
|
|
92
|
+
"ArrowDown",
|
|
93
|
+
"Home",
|
|
94
|
+
"End",
|
|
95
|
+
"PageUp",
|
|
96
|
+
"PageDown"
|
|
97
|
+
]);
|
|
98
|
+
let lastIsTouchInput = false;
|
|
99
|
+
let lastIsPointerSelection = false;
|
|
100
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
101
|
+
function setIsTouchInput(isTouchInput) {
|
|
102
|
+
if (isTouchInput === lastIsTouchInput) return;
|
|
103
|
+
lastIsTouchInput = isTouchInput;
|
|
104
|
+
for (const listener of listeners) listener();
|
|
105
|
+
}
|
|
106
|
+
function handlePointerDown(event) {
|
|
107
|
+
const target = event.target;
|
|
108
|
+
lastIsPointerSelection = target instanceof Element && !!target.closest(".ProseMirror");
|
|
109
|
+
const pointerType = event.pointerType;
|
|
110
|
+
if (pointerType === "mouse") setIsTouchInput(false);
|
|
111
|
+
else if (pointerType === "touch" || pointerType === "pen") setIsTouchInput(true);
|
|
112
|
+
}
|
|
113
|
+
function handleKeyDown(event) {
|
|
114
|
+
if (getIsComposing() || event.isComposing) return;
|
|
115
|
+
lastIsPointerSelection = false;
|
|
116
|
+
if (KEYBOARD_MODALITY_KEYS.has(event.key) || event.metaKey || event.ctrlKey) setIsTouchInput(false);
|
|
117
|
+
}
|
|
118
|
+
if (typeof window !== "undefined") {
|
|
119
|
+
window.addEventListener("pointerdown", handlePointerDown, {
|
|
120
|
+
capture: true,
|
|
121
|
+
passive: true
|
|
122
|
+
});
|
|
123
|
+
window.addEventListener("keydown", handleKeyDown, {
|
|
124
|
+
capture: true,
|
|
125
|
+
passive: true
|
|
126
|
+
});
|
|
127
|
+
}
|
|
88
128
|
/**
|
|
89
|
-
* Whether the
|
|
129
|
+
* Whether the user last drove the selection with a finger (or pen) on the
|
|
130
|
+
* screen, as opposed to precise input (hardware keyboard navigation).
|
|
90
131
|
*
|
|
91
|
-
*
|
|
132
|
+
* Starts as `false` and follows the events; a touch device flips it on the
|
|
133
|
+
* first tap, which necessarily precedes any caret. Only navigation keys and
|
|
134
|
+
* modifier combos flip it back: letter keys are ignored because a software
|
|
135
|
+
* keyboard sends them too, and the software keyboard's own caret gestures (a
|
|
136
|
+
* spacebar long-press drag) reach the page as bare `selectionchange` events
|
|
137
|
+
* with no key or touch events at all, so staying on the previous value is the
|
|
138
|
+
* correct reading for them.
|
|
139
|
+
*/
|
|
140
|
+
function getIsTouchInput() {
|
|
141
|
+
return lastIsTouchInput;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Whether the next selection change in an editor comes from a pointer: the
|
|
145
|
+
* last `pointerdown` landed inside an editor and no key was pressed since.
|
|
92
146
|
*/
|
|
93
|
-
function
|
|
94
|
-
return
|
|
147
|
+
function getIsPointerSelection() {
|
|
148
|
+
return lastIsPointerSelection;
|
|
95
149
|
}
|
|
96
150
|
/**
|
|
151
|
+
* Calls `listener` whenever {@link getIsTouchInput} may report a new value.
|
|
152
|
+
*/
|
|
153
|
+
function onIsTouchInputChange(listener) {
|
|
154
|
+
listeners.add(listener);
|
|
155
|
+
return () => {
|
|
156
|
+
listeners.delete(listener);
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
//#endregion
|
|
161
|
+
//#region src/utils/transaction.ts
|
|
162
|
+
/**
|
|
97
163
|
* Whether any of the given transactions are selection transactions directly caused by mouse or touch input.
|
|
98
164
|
*/
|
|
99
165
|
function hasPointerSelectionTransaction(transactions) {
|
|
100
|
-
return transactions.some(
|
|
166
|
+
return getIsPointerSelection() && transactions.some((tr) => tr.selectionSet && !tr.docChanged);
|
|
101
167
|
}
|
|
102
168
|
|
|
103
169
|
//#endregion
|
|
@@ -512,9 +578,8 @@ function createCaretSnapPlugin(marks) {
|
|
|
512
578
|
if (markNames.length === 0) return null;
|
|
513
579
|
const selection = newState.selection;
|
|
514
580
|
if (!isTextSelection(selection)) return null;
|
|
515
|
-
const isPointer = hasPointerSelectionTransaction(transactions);
|
|
516
581
|
if (!selection.empty) {
|
|
517
|
-
if (!
|
|
582
|
+
if (!hasPointerSelectionTransaction(transactions)) return null;
|
|
518
583
|
const from = getMarkRangeStrictlyAround(newState, selection.from, markNames)?.from ?? selection.from;
|
|
519
584
|
const to = getMarkRangeStrictlyAround(newState, selection.to, markNames)?.to ?? selection.to;
|
|
520
585
|
if (from === selection.from && to === selection.to) return null;
|
|
@@ -524,6 +589,7 @@ function createCaretSnapPlugin(marks) {
|
|
|
524
589
|
}
|
|
525
590
|
const range = getMarkRangeStrictlyAround(newState, selection.head, markNames);
|
|
526
591
|
if (!range) return null;
|
|
592
|
+
const isPointer = hasPointerSelectionTransaction(transactions);
|
|
527
593
|
const head = getUnitEdge(range, oldState.selection.head, selection.head, isPointer);
|
|
528
594
|
return newState.tr.setSelection(TextSelection.create(newState.doc, head));
|
|
529
595
|
}
|
|
@@ -614,6 +680,9 @@ function handleMouseDown(view, event) {
|
|
|
614
680
|
const { doc } = view.state;
|
|
615
681
|
const lastBlock = doc.lastChild;
|
|
616
682
|
if (!lastBlock || acceptsCaretAtEnd(lastBlock)) return false;
|
|
683
|
+
let bottom = lastBlock;
|
|
684
|
+
while (bottom && !bottom.isTextblock && !isNodeOfType(bottom, "table")) bottom = bottom.lastChild;
|
|
685
|
+
if (bottom && bottom.content.size === 0 && acceptsCaretAtEnd(bottom)) return false;
|
|
617
686
|
const lastBlockDOM = view.nodeDOM(doc.content.size - lastBlock.nodeSize);
|
|
618
687
|
if (!(lastBlockDOM instanceof HTMLElement)) return false;
|
|
619
688
|
if (event.clientY <= lastBlockDOM.getBoundingClientRect().bottom) return false;
|
|
@@ -628,7 +697,8 @@ function handleMouseDown(view, event) {
|
|
|
628
697
|
}
|
|
629
698
|
/**
|
|
630
699
|
* A press below the last block appends an empty paragraph and puts the caret
|
|
631
|
-
* in it, when that block would otherwise keep the caret inside itself
|
|
700
|
+
* in it, when that block would otherwise keep the caret inside itself and
|
|
701
|
+
* does not end in an empty line.
|
|
632
702
|
*/
|
|
633
703
|
function defineClickBelow() {
|
|
634
704
|
return definePlugin(new Plugin({
|
|
@@ -3469,8 +3539,8 @@ function createSnapPlugin() {
|
|
|
3469
3539
|
if (getMarkMode(newState) !== "hide") return null;
|
|
3470
3540
|
const selection = newState.selection;
|
|
3471
3541
|
if (!isTextSelection(selection)) return null;
|
|
3472
|
-
const isPointer = hasPointerSelectionTransaction(transactions);
|
|
3473
3542
|
if (selection.empty) {
|
|
3543
|
+
const isPointer = hasPointerSelectionTransaction(transactions);
|
|
3474
3544
|
const next = getRestPosition(newState, oldState.selection.head, selection.head, isPointer);
|
|
3475
3545
|
if (next === selection.head) return null;
|
|
3476
3546
|
return newState.tr.setSelection(TextSelection.create(newState.doc, next));
|
|
@@ -8478,32 +8548,29 @@ const EDITOR_KEY_BINDINGS = {
|
|
|
8478
8548
|
|
|
8479
8549
|
//#endregion
|
|
8480
8550
|
//#region src/extensions/mark-hover.ts
|
|
8551
|
+
const IDLE = { kind: "idle" };
|
|
8552
|
+
function getHit(phase) {
|
|
8553
|
+
return phase.kind === "active" || phase.kind === "leaving" ? phase.hit : void 0;
|
|
8554
|
+
}
|
|
8481
8555
|
/**
|
|
8482
|
-
*
|
|
8483
|
-
*
|
|
8484
|
-
* Movement within a mark is de-duplicated. The active hit is also revalidated
|
|
8485
|
-
* after every editor update, so deleting, replacing, or rewriting a hovered
|
|
8486
|
-
* mark emits leave even when the pointer itself never moves. Destroying the
|
|
8487
|
-
* editor or removing the extension emits leave as well.
|
|
8488
|
-
*
|
|
8489
|
-
* With `tap`, a touch tap enters too. The browser is the tap recognizer:
|
|
8490
|
-
* only a recognized stationary single-finger tap synthesizes the
|
|
8491
|
-
* compatibility mouse events and the trailing `click`; scrolls, drags,
|
|
8492
|
-
* long-presses, and multi-finger gestures never produce them.
|
|
8556
|
+
* The tracked element the pointer is on, if any.
|
|
8493
8557
|
*/
|
|
8494
|
-
function
|
|
8495
|
-
|
|
8558
|
+
function getPointerElement(phase) {
|
|
8559
|
+
switch (phase.kind) {
|
|
8560
|
+
case "pending":
|
|
8561
|
+
case "dismissed": return phase.element;
|
|
8562
|
+
case "active": return phase.hit.element;
|
|
8563
|
+
default: return;
|
|
8564
|
+
}
|
|
8565
|
+
}
|
|
8566
|
+
function createHoverTracker(config) {
|
|
8567
|
+
const { openDelay, closeDelay } = config;
|
|
8568
|
+
let phase = IDLE;
|
|
8496
8569
|
/**
|
|
8497
|
-
*
|
|
8570
|
+
* Runs exactly while the phase is `pending` or `leaving`.
|
|
8498
8571
|
*/
|
|
8499
|
-
let emitted;
|
|
8500
8572
|
let timer;
|
|
8501
8573
|
/**
|
|
8502
|
-
* The element of a scheduled enter, `null` for a scheduled leave,
|
|
8503
|
-
* `undefined` when nothing is scheduled.
|
|
8504
|
-
*/
|
|
8505
|
-
let scheduledElement;
|
|
8506
|
-
/**
|
|
8507
8574
|
* The type of the pointer that spawned the current event sequence:
|
|
8508
8575
|
* compatibility mouse events carry no pointer type of their own.
|
|
8509
8576
|
*/
|
|
@@ -8514,127 +8581,201 @@ function defineMarkHoverHandler(config) {
|
|
|
8514
8581
|
const findPayloadForElement = (view, element) => {
|
|
8515
8582
|
return config.findPayloadForElement ? config.findPayloadForElement(view, element) : config.findPayloadAt(view.state, view.posAtDOM(element, 0));
|
|
8516
8583
|
};
|
|
8517
|
-
|
|
8584
|
+
/**
|
|
8585
|
+
* The only transition. It restarts the timer the next phase needs and
|
|
8586
|
+
* reports a change of the hit element.
|
|
8587
|
+
*/
|
|
8588
|
+
const go = (next) => {
|
|
8518
8589
|
clearTimeout(timer);
|
|
8519
|
-
|
|
8590
|
+
const previousHit = getHit(phase);
|
|
8591
|
+
phase = next;
|
|
8592
|
+
if (next.kind === "pending") timer = setTimeout(finishOpen, openDelay);
|
|
8593
|
+
if (next.kind === "leaving") timer = setTimeout(finishLeave, closeDelay);
|
|
8594
|
+
const hit = getHit(next);
|
|
8595
|
+
if (hit?.element !== previousHit?.element) config.onHoverChange(hit);
|
|
8520
8596
|
};
|
|
8521
|
-
const
|
|
8522
|
-
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
|
|
8597
|
+
const finishOpen = () => {
|
|
8598
|
+
if (phase.kind !== "pending") return;
|
|
8599
|
+
const { element, view } = phase;
|
|
8600
|
+
const payload = element.isConnected ? findPayloadForElement(view, element) : void 0;
|
|
8601
|
+
go(payload == null ? IDLE : {
|
|
8602
|
+
kind: "active",
|
|
8603
|
+
hit: {
|
|
8604
|
+
payload,
|
|
8605
|
+
element
|
|
8606
|
+
}
|
|
8607
|
+
});
|
|
8608
|
+
};
|
|
8609
|
+
const finishLeave = () => {
|
|
8610
|
+
if (phase.kind !== "leaving") return;
|
|
8611
|
+
go(config.canLeave?.() === false ? phase : IDLE);
|
|
8612
|
+
};
|
|
8613
|
+
const startPending = (view, element) => {
|
|
8614
|
+
if (findPayloadForElement(view, element) == null) return;
|
|
8615
|
+
go({
|
|
8616
|
+
kind: "pending",
|
|
8617
|
+
element,
|
|
8618
|
+
view
|
|
8619
|
+
});
|
|
8526
8620
|
};
|
|
8527
|
-
const
|
|
8528
|
-
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
|
|
8621
|
+
const handleOver = (view, event) => {
|
|
8622
|
+
const element = findClosestMark(event.target);
|
|
8623
|
+
if (!element || !view.dom.contains(element)) return;
|
|
8624
|
+
switch (phase.kind) {
|
|
8625
|
+
case "idle": return startPending(view, element);
|
|
8626
|
+
case "pending":
|
|
8627
|
+
case "dismissed":
|
|
8628
|
+
if (element !== phase.element) startPending(view, element);
|
|
8629
|
+
return;
|
|
8630
|
+
case "active":
|
|
8631
|
+
case "leaving": {
|
|
8632
|
+
if (element === phase.hit.element) return go({
|
|
8633
|
+
kind: "active",
|
|
8634
|
+
hit: phase.hit
|
|
8635
|
+
});
|
|
8636
|
+
const payload = findPayloadForElement(view, element);
|
|
8637
|
+
if (payload != null) go({
|
|
8638
|
+
kind: "active",
|
|
8639
|
+
hit: {
|
|
8640
|
+
payload,
|
|
8641
|
+
element
|
|
8642
|
+
}
|
|
8643
|
+
});
|
|
8533
8644
|
return;
|
|
8534
8645
|
}
|
|
8535
|
-
|
|
8536
|
-
};
|
|
8537
|
-
timer = setTimeout(fire, closeDelay);
|
|
8646
|
+
}
|
|
8538
8647
|
};
|
|
8539
|
-
const
|
|
8648
|
+
const handleOut = (event) => {
|
|
8649
|
+
const element = getPointerElement(phase);
|
|
8650
|
+
if (!element) return;
|
|
8651
|
+
const related = event.relatedTarget;
|
|
8652
|
+
if (related instanceof Node && element.contains(related)) return;
|
|
8653
|
+
go(phase.kind === "active" ? {
|
|
8654
|
+
kind: "leaving",
|
|
8655
|
+
hit: phase.hit
|
|
8656
|
+
} : IDLE);
|
|
8657
|
+
};
|
|
8658
|
+
const handlePointerDown = (event) => {
|
|
8659
|
+
lastPointerType = event.pointerType;
|
|
8660
|
+
};
|
|
8661
|
+
const handleMouseDown = (event) => {
|
|
8662
|
+
if (lastPointerType !== "touch" || !findClosestMark(event.target)) return false;
|
|
8663
|
+
event.preventDefault();
|
|
8664
|
+
return true;
|
|
8665
|
+
};
|
|
8666
|
+
const handleClick = (view, event) => {
|
|
8667
|
+
if (lastPointerType !== "touch") return false;
|
|
8668
|
+
const element = findClosestMark(event.target);
|
|
8669
|
+
if (!element || !view.dom.contains(element)) {
|
|
8670
|
+
go(IDLE);
|
|
8671
|
+
return false;
|
|
8672
|
+
}
|
|
8673
|
+
event.preventDefault();
|
|
8540
8674
|
const payload = findPayloadForElement(view, element);
|
|
8541
|
-
if (payload
|
|
8542
|
-
|
|
8543
|
-
|
|
8675
|
+
if (payload != null) go({
|
|
8676
|
+
kind: "active",
|
|
8677
|
+
hit: {
|
|
8544
8678
|
payload,
|
|
8545
8679
|
element
|
|
8546
|
-
}
|
|
8680
|
+
}
|
|
8681
|
+
});
|
|
8682
|
+
return true;
|
|
8683
|
+
};
|
|
8684
|
+
const update = (view) => {
|
|
8685
|
+
if (phase.kind === "dismissed") {
|
|
8686
|
+
if (!view.dom.contains(phase.element)) go(IDLE);
|
|
8547
8687
|
return;
|
|
8548
8688
|
}
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
|
|
8555
|
-
|
|
8556
|
-
|
|
8557
|
-
|
|
8558
|
-
payload: fresh,
|
|
8689
|
+
if (phase.kind !== "active" && phase.kind !== "leaving") return;
|
|
8690
|
+
const { element } = phase.hit;
|
|
8691
|
+
if (!element.isConnected || !view.dom.contains(element)) return go(IDLE);
|
|
8692
|
+
const payload = findPayloadForElement(view, element);
|
|
8693
|
+
if (payload == null || !config.isSamePayload(phase.hit.payload, payload)) return go(IDLE);
|
|
8694
|
+
phase = {
|
|
8695
|
+
kind: phase.kind,
|
|
8696
|
+
hit: {
|
|
8697
|
+
payload,
|
|
8559
8698
|
element
|
|
8560
|
-
}
|
|
8561
|
-
}
|
|
8699
|
+
}
|
|
8700
|
+
};
|
|
8562
8701
|
};
|
|
8563
|
-
const
|
|
8564
|
-
|
|
8565
|
-
|
|
8566
|
-
|
|
8567
|
-
|
|
8568
|
-
|
|
8702
|
+
const dismiss = () => {
|
|
8703
|
+
switch (phase.kind) {
|
|
8704
|
+
case "pending": return go({
|
|
8705
|
+
kind: "dismissed",
|
|
8706
|
+
element: phase.element
|
|
8707
|
+
});
|
|
8708
|
+
case "active": return go({
|
|
8709
|
+
kind: "dismissed",
|
|
8710
|
+
element: phase.hit.element
|
|
8711
|
+
});
|
|
8712
|
+
case "leaving": return go(IDLE);
|
|
8569
8713
|
}
|
|
8570
|
-
if (element === scheduledElement) return;
|
|
8571
|
-
enter(view, element);
|
|
8572
8714
|
};
|
|
8573
|
-
|
|
8574
|
-
|
|
8575
|
-
|
|
8576
|
-
|
|
8577
|
-
|
|
8578
|
-
|
|
8579
|
-
|
|
8715
|
+
return {
|
|
8716
|
+
handleOver,
|
|
8717
|
+
handleOut,
|
|
8718
|
+
handlePointerDown,
|
|
8719
|
+
handleMouseDown,
|
|
8720
|
+
handleClick,
|
|
8721
|
+
update,
|
|
8722
|
+
dismiss,
|
|
8723
|
+
destroy: () => go(IDLE)
|
|
8580
8724
|
};
|
|
8725
|
+
}
|
|
8726
|
+
/**
|
|
8727
|
+
* Delegate hover tracking for a rendered mark to the editor root.
|
|
8728
|
+
*
|
|
8729
|
+
* Movement within a mark is de-duplicated. The active hit is also revalidated
|
|
8730
|
+
* after every editor update, so deleting, replacing, or rewriting a hovered
|
|
8731
|
+
* mark emits leave even when the pointer itself never moves. Destroying the
|
|
8732
|
+
* editor or removing the extension emits leave as well.
|
|
8733
|
+
*
|
|
8734
|
+
* With `tap`, a touch tap enters too. The browser is the tap recognizer:
|
|
8735
|
+
* only a recognized stationary single-finger tap synthesizes the
|
|
8736
|
+
* compatibility mouse events and the trailing `click`; scrolls, drags,
|
|
8737
|
+
* long-presses, and multi-finger gestures never produce them.
|
|
8738
|
+
*
|
|
8739
|
+
* The tracker lives in the plugin state, so `key.getState(state)?.dismiss()`
|
|
8740
|
+
* reaches the one tracking that editor.
|
|
8741
|
+
*/
|
|
8742
|
+
function defineMarkHoverHandler(config) {
|
|
8743
|
+
const { key } = config;
|
|
8581
8744
|
return definePlugin(new Plugin({
|
|
8582
|
-
key
|
|
8745
|
+
key,
|
|
8746
|
+
state: {
|
|
8747
|
+
init: () => createHoverTracker(config),
|
|
8748
|
+
apply: (_tr, tracker) => tracker
|
|
8749
|
+
},
|
|
8583
8750
|
props: { handleDOMEvents: {
|
|
8584
8751
|
mouseover: (view, event) => {
|
|
8585
|
-
handleOver(view, event);
|
|
8752
|
+
key.getState(view.state)?.handleOver(view, event);
|
|
8586
8753
|
return false;
|
|
8587
8754
|
},
|
|
8588
|
-
mouseout: (
|
|
8589
|
-
handleOut(event);
|
|
8755
|
+
mouseout: (view, event) => {
|
|
8756
|
+
key.getState(view.state)?.handleOut(event);
|
|
8590
8757
|
return false;
|
|
8591
8758
|
},
|
|
8592
|
-
...tap && {
|
|
8593
|
-
pointerdown: (
|
|
8594
|
-
|
|
8759
|
+
...config.tap && {
|
|
8760
|
+
pointerdown: (view, event) => {
|
|
8761
|
+
key.getState(view.state)?.handlePointerDown(event);
|
|
8595
8762
|
return false;
|
|
8596
8763
|
},
|
|
8597
|
-
mousedown: (
|
|
8598
|
-
|
|
8599
|
-
event.preventDefault();
|
|
8600
|
-
return true;
|
|
8764
|
+
mousedown: (view, event) => {
|
|
8765
|
+
return key.getState(view.state)?.handleMouseDown(event) ?? false;
|
|
8601
8766
|
},
|
|
8602
8767
|
click: (view, event) => {
|
|
8603
|
-
|
|
8604
|
-
const element = findClosestMark(event.target);
|
|
8605
|
-
if (!element || !view.dom.contains(element)) {
|
|
8606
|
-
emit(void 0);
|
|
8607
|
-
return false;
|
|
8608
|
-
}
|
|
8609
|
-
event.preventDefault();
|
|
8610
|
-
const payload = findPayloadForElement(view, element);
|
|
8611
|
-
if (payload != null) emit({
|
|
8612
|
-
payload,
|
|
8613
|
-
element
|
|
8614
|
-
});
|
|
8615
|
-
return true;
|
|
8768
|
+
return key.getState(view.state)?.handleClick(view, event) ?? false;
|
|
8616
8769
|
}
|
|
8617
8770
|
}
|
|
8618
8771
|
} },
|
|
8619
|
-
view: () =>
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
|
|
8623
|
-
|
|
8624
|
-
|
|
8625
|
-
|
|
8626
|
-
const payload = findPayloadForElement(view, emitted.element);
|
|
8627
|
-
if (payload == null || !config.isSamePayload(emitted.payload, payload)) {
|
|
8628
|
-
emit(void 0);
|
|
8629
|
-
return;
|
|
8630
|
-
}
|
|
8631
|
-
emitted = {
|
|
8632
|
-
...emitted,
|
|
8633
|
-
payload
|
|
8634
|
-
};
|
|
8635
|
-
},
|
|
8636
|
-
destroy: () => emit(void 0)
|
|
8637
|
-
})
|
|
8772
|
+
view: (view) => {
|
|
8773
|
+
const tracker = key.getState(view.state);
|
|
8774
|
+
return {
|
|
8775
|
+
update: (view) => tracker?.update(view),
|
|
8776
|
+
destroy: () => tracker?.destroy()
|
|
8777
|
+
};
|
|
8778
|
+
}
|
|
8638
8779
|
}));
|
|
8639
8780
|
}
|
|
8640
8781
|
|
|
@@ -8674,6 +8815,14 @@ function defineLinkHoverHandler(onHoverChange, { canLeave } = {}) {
|
|
|
8674
8815
|
onHoverChange
|
|
8675
8816
|
});
|
|
8676
8817
|
}
|
|
8818
|
+
/**
|
|
8819
|
+
* Tell the link hover handler that the user dismissed the UI it opened. The
|
|
8820
|
+
* link under the pointer stays silent until the pointer leaves it, so a
|
|
8821
|
+
* pending hover cannot reopen the UI.
|
|
8822
|
+
*/
|
|
8823
|
+
function dismissLinkHover(state) {
|
|
8824
|
+
linkHoverKey.getState(state)?.dismiss();
|
|
8825
|
+
}
|
|
8677
8826
|
|
|
8678
8827
|
//#endregion
|
|
8679
8828
|
//#region src/utils/force-reflow.ts
|
|
@@ -8681,69 +8830,6 @@ function forceReflow(element) {
|
|
|
8681
8830
|
element.offsetWidth;
|
|
8682
8831
|
}
|
|
8683
8832
|
|
|
8684
|
-
//#endregion
|
|
8685
|
-
//#region src/utils/input-modality.ts
|
|
8686
|
-
const KEYBOARD_MODALITY_KEYS = /* @__PURE__ */ new Set([
|
|
8687
|
-
"ArrowLeft",
|
|
8688
|
-
"ArrowRight",
|
|
8689
|
-
"ArrowUp",
|
|
8690
|
-
"ArrowDown",
|
|
8691
|
-
"Home",
|
|
8692
|
-
"End",
|
|
8693
|
-
"PageUp",
|
|
8694
|
-
"PageDown"
|
|
8695
|
-
]);
|
|
8696
|
-
let lastIsTouchInput = false;
|
|
8697
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
8698
|
-
function setIsTouchInput(isTouchInput) {
|
|
8699
|
-
if (isTouchInput === lastIsTouchInput) return;
|
|
8700
|
-
lastIsTouchInput = isTouchInput;
|
|
8701
|
-
for (const listener of listeners) listener();
|
|
8702
|
-
}
|
|
8703
|
-
function handlePointerDown(event) {
|
|
8704
|
-
const pointerType = event.pointerType;
|
|
8705
|
-
if (pointerType === "mouse") setIsTouchInput(false);
|
|
8706
|
-
else if (pointerType === "touch" || pointerType === "pen") setIsTouchInput(true);
|
|
8707
|
-
}
|
|
8708
|
-
function handleKeyDown(event) {
|
|
8709
|
-
if (getIsComposing() || event.isComposing) return;
|
|
8710
|
-
if (KEYBOARD_MODALITY_KEYS.has(event.key) || event.metaKey || event.ctrlKey) setIsTouchInput(false);
|
|
8711
|
-
}
|
|
8712
|
-
if (typeof window !== "undefined") {
|
|
8713
|
-
window.addEventListener("pointerdown", handlePointerDown, {
|
|
8714
|
-
capture: true,
|
|
8715
|
-
passive: true
|
|
8716
|
-
});
|
|
8717
|
-
window.addEventListener("keydown", handleKeyDown, {
|
|
8718
|
-
capture: true,
|
|
8719
|
-
passive: true
|
|
8720
|
-
});
|
|
8721
|
-
}
|
|
8722
|
-
/**
|
|
8723
|
-
* Whether the user last drove the selection with a finger (or pen) on the
|
|
8724
|
-
* screen, as opposed to precise input (hardware keyboard navigation).
|
|
8725
|
-
*
|
|
8726
|
-
* Starts as `false` and follows the events; a touch device flips it on the
|
|
8727
|
-
* first tap, which necessarily precedes any caret. Only navigation keys and
|
|
8728
|
-
* modifier combos flip it back: letter keys are ignored because a software
|
|
8729
|
-
* keyboard sends them too, and the software keyboard's own caret gestures (a
|
|
8730
|
-
* spacebar long-press drag) reach the page as bare `selectionchange` events
|
|
8731
|
-
* with no key or touch events at all, so staying on the previous value is the
|
|
8732
|
-
* correct reading for them.
|
|
8733
|
-
*/
|
|
8734
|
-
function getIsTouchInput() {
|
|
8735
|
-
return lastIsTouchInput;
|
|
8736
|
-
}
|
|
8737
|
-
/**
|
|
8738
|
-
* Calls `listener` whenever {@link getIsTouchInput} may report a new value.
|
|
8739
|
-
*/
|
|
8740
|
-
function onIsTouchInputChange(listener) {
|
|
8741
|
-
listeners.add(listener);
|
|
8742
|
-
return () => {
|
|
8743
|
-
listeners.delete(listener);
|
|
8744
|
-
};
|
|
8745
|
-
}
|
|
8746
|
-
|
|
8747
8833
|
//#endregion
|
|
8748
8834
|
//#region src/extensions/virtual-caret.ts
|
|
8749
8835
|
const key = new PluginKey("meowdown-virtual-caret");
|
|
@@ -9041,4 +9127,4 @@ function getVirtualElementFromRange(view, range) {
|
|
|
9041
9127
|
}
|
|
9042
9128
|
|
|
9043
9129
|
//#endregion
|
|
9044
|
-
export { EDITOR_KEY_BINDINGS, Priority, buildFileMarkdown, checkRoundTrip, codeBlockLanguages, collectReferenceDefinitions, defaultResolveImageUrl, defaultResolveXPost, defaultResolveYouTubeVideo, defineBulletAfterHeading, defineCodeBlockPreviewPlugin, defineCodeBlockSyntaxHighlight, defineEditorExtension, defineEmbedPaste, defineExitBoundaryHandler, defineFileClickHandler, defineFilePaste, defineFileView, defineFollowLinkHandler, defineHTMLComment, defineImage, defineImageClickHandler, defineLinkClickHandler, defineLinkCommands, defineLinkEditKeymap, defineLinkHoverHandler, defineLinkPaste, defineMath, definePendingReplacementHandler, definePlaceholder, defineReadonly, defineSearchStatusHandler, defineSubstitution, defineTagClickHandler, defineViewAttributes, defineVirtualCaret, defineWikilinkClickHandler, defineWikilinkHoverHandler, defineWikilinkTrigger, defineXPostMediaClickHandler, defineYouTubeVideoClickHandler, docToMarkdown, formatFileSize, formatSizedWikiEmbed, getCodeTokens, getEditorConfig, getFileKind, getIsComposing, getLinkText, getLinkUnitAt, getMarkBuilders, getPendingReplacement, getSearchStatus, getSelectedText, getTableColumnAlign, getTextblockDisplayText, getVirtualElementFromRange, inlineTextToMarkChunks, inlineTextToMarkChunksWithContext, insertLink, isCodeBlockPreviewHiddenDecoration, isLinkTextForHref, isMarkOfType, isModEvent, isNodeOfType, isReferenceDefinitionNode, isSelectionInTableCell, loadKaTeX, markdownToDoc, normalizeHref, parsePostEmbedSnapshot, parseWikiEmbed, removeLink, renderMathInto, updateEditorConfig, updateLink, wikiEmbedBasename, withPriority };
|
|
9130
|
+
export { EDITOR_KEY_BINDINGS, Priority, buildFileMarkdown, checkRoundTrip, codeBlockLanguages, collectReferenceDefinitions, defaultResolveImageUrl, defaultResolveXPost, defaultResolveYouTubeVideo, defineBulletAfterHeading, defineCodeBlockPreviewPlugin, defineCodeBlockSyntaxHighlight, defineEditorExtension, defineEmbedPaste, defineExitBoundaryHandler, defineFileClickHandler, defineFilePaste, defineFileView, defineFollowLinkHandler, defineHTMLComment, defineImage, defineImageClickHandler, defineLinkClickHandler, defineLinkCommands, defineLinkEditKeymap, defineLinkHoverHandler, defineLinkPaste, defineMath, definePendingReplacementHandler, definePlaceholder, defineReadonly, defineSearchStatusHandler, defineSubstitution, defineTagClickHandler, defineViewAttributes, defineVirtualCaret, defineWikilinkClickHandler, defineWikilinkHoverHandler, defineWikilinkTrigger, defineXPostMediaClickHandler, defineYouTubeVideoClickHandler, dismissLinkHover, docToMarkdown, formatFileSize, formatSizedWikiEmbed, getCodeTokens, getEditorConfig, getFileKind, getIsComposing, getLinkText, getLinkUnitAt, getMarkBuilders, getPendingReplacement, getSearchStatus, getSelectedText, getTableColumnAlign, getTextblockDisplayText, getVirtualElementFromRange, inlineTextToMarkChunks, inlineTextToMarkChunksWithContext, insertLink, isCodeBlockPreviewHiddenDecoration, isLinkTextForHref, isMarkOfType, isModEvent, isNodeOfType, isReferenceDefinitionNode, isSelectionInTableCell, loadKaTeX, markdownToDoc, normalizeHref, parsePostEmbedSnapshot, parseWikiEmbed, removeLink, renderMathInto, updateEditorConfig, updateLink, wikiEmbedBasename, withPriority };
|