@h-k-dev/angular-email-editor 0.0.2 → 0.0.3
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.
|
@@ -15626,12 +15626,16 @@ const createBubbleMenu = (options) => defineExtension({
|
|
|
15626
15626
|
let mouseSelecting = false;
|
|
15627
15627
|
let destroyed = false;
|
|
15628
15628
|
let open = false;
|
|
15629
|
+
// Where the open menu stands (`anchor: 'first'`): the range or the
|
|
15630
|
+
// node it opened over, and the box measured there.
|
|
15631
|
+
let pinned = null;
|
|
15629
15632
|
// Closed is said once: a caret moving through the text, or a press
|
|
15630
15633
|
// elsewhere on the page, is no news to a host that already knows.
|
|
15631
15634
|
const close = () => {
|
|
15632
15635
|
if (!open)
|
|
15633
15636
|
return;
|
|
15634
15637
|
open = false;
|
|
15638
|
+
pinned = null;
|
|
15635
15639
|
options.onStateChange({ isOpen: false, boundingBox: null });
|
|
15636
15640
|
};
|
|
15637
15641
|
// Whether the menu may show: not mid-drag, the host's say-so, and
|
|
@@ -15641,40 +15645,16 @@ const createBubbleMenu = (options) => defineExtension({
|
|
|
15641
15645
|
!mouseSelecting &&
|
|
15642
15646
|
(options.shouldShow || defaultBubbleShouldShow)(view.state) &&
|
|
15643
15647
|
view.hasFocus();
|
|
15644
|
-
//
|
|
15645
|
-
|
|
15646
|
-
|
|
15647
|
-
// have opened something of its own there (a click on a button
|
|
15648
|
-
// opens its link editor) that its `shouldShow` now says no to.
|
|
15649
|
-
if (!canShow())
|
|
15650
|
-
return close();
|
|
15651
|
-
// An image alone, or a button: the menu stands over the node
|
|
15652
|
-
// itself.
|
|
15653
|
-
const image = selectedImage(view.state);
|
|
15654
|
-
const button = image ? null : selectedButton(view.state);
|
|
15655
|
-
const node = image ?? button;
|
|
15656
|
-
const dom = node && view.nodeDOM(node.pos);
|
|
15657
|
-
if (dom && typeof dom.getBoundingClientRect === 'function') {
|
|
15658
|
-
open = true;
|
|
15659
|
-
options.onStateChange({
|
|
15660
|
-
isOpen: true,
|
|
15661
|
-
boundingBox: dom.getBoundingClientRect(),
|
|
15662
|
-
kind: image ? 'image' : 'button',
|
|
15663
|
-
});
|
|
15664
|
-
return;
|
|
15665
|
-
}
|
|
15666
|
-
const { from, to } = view.state.selection;
|
|
15667
|
-
// Get coordinates of the selection boundaries
|
|
15648
|
+
// The box of a range: from its start to its end, over every line it
|
|
15649
|
+
// takes — the virtual DOMRect the host's overlay anchors to.
|
|
15650
|
+
const rangeBox = (from, to) => {
|
|
15668
15651
|
const start = view.coordsAtPos(from);
|
|
15669
15652
|
const end = view.coordsAtPos(to, -1);
|
|
15670
|
-
// Construct a virtual DOMRect representing the text selection.
|
|
15671
|
-
// Angular CDK uses this to anchor the overlay!
|
|
15672
15653
|
const top = Math.min(start.top, end.top);
|
|
15673
15654
|
const bottom = Math.max(start.bottom, end.bottom);
|
|
15674
15655
|
const left = Math.min(start.left, end.left);
|
|
15675
15656
|
const right = Math.max(start.right, end.right);
|
|
15676
|
-
|
|
15677
|
-
const boundingBox = {
|
|
15657
|
+
return {
|
|
15678
15658
|
top,
|
|
15679
15659
|
bottom,
|
|
15680
15660
|
left,
|
|
@@ -15685,8 +15665,51 @@ const createBubbleMenu = (options) => defineExtension({
|
|
|
15685
15665
|
y: top,
|
|
15686
15666
|
toJSON: () => '',
|
|
15687
15667
|
};
|
|
15668
|
+
};
|
|
15669
|
+
// The box of a node: its own element's, while it has one.
|
|
15670
|
+
const nodeBox = (pos) => {
|
|
15671
|
+
const dom = view.nodeDOM(pos);
|
|
15672
|
+
return dom && typeof dom.getBoundingClientRect === 'function'
|
|
15673
|
+
? dom.getBoundingClientRect()
|
|
15674
|
+
: null;
|
|
15675
|
+
};
|
|
15676
|
+
// Reports the menu open over the current selection — standing
|
|
15677
|
+
// where it opened (`anchor: 'first'`), or over the selection of
|
|
15678
|
+
// the moment. `remeasure`: the pinned place has moved on screen
|
|
15679
|
+
// (a scroll), so its box is measured again.
|
|
15680
|
+
const show = (remeasure = false) => {
|
|
15681
|
+
// Asked again once the delay is over: in between, the host may
|
|
15682
|
+
// have opened something of its own there (a click on a button
|
|
15683
|
+
// opens its link editor) that its `shouldShow` now says no to.
|
|
15684
|
+
if (!canShow())
|
|
15685
|
+
return close();
|
|
15686
|
+
// An image alone, or a button: the menu is for the node, and
|
|
15687
|
+
// stands over the node itself — while it has an element to
|
|
15688
|
+
// stand over; text otherwise.
|
|
15689
|
+
const image = selectedImage(view.state);
|
|
15690
|
+
const button = image ? null : selectedButton(view.state);
|
|
15691
|
+
const node = image ?? button;
|
|
15692
|
+
const box = node ? nodeBox(node.pos) : null;
|
|
15693
|
+
const kind = box ? (image ? 'image' : 'button') : 'text';
|
|
15694
|
+
if (pinned && (options.anchor ?? 'first') === 'first') {
|
|
15695
|
+
if (remeasure) {
|
|
15696
|
+
// The same place, where it now is — clamped, in case the
|
|
15697
|
+
// document shrank under it since.
|
|
15698
|
+
const size = view.state.doc.content.size;
|
|
15699
|
+
const from = Math.min(pinned.from, size);
|
|
15700
|
+
pinned.box =
|
|
15701
|
+
(pinned.node ? nodeBox(from) : rangeBox(from, Math.min(pinned.to, size))) ??
|
|
15702
|
+
pinned.box;
|
|
15703
|
+
}
|
|
15704
|
+
options.onStateChange({ isOpen: true, boundingBox: pinned.box, kind });
|
|
15705
|
+
return;
|
|
15706
|
+
}
|
|
15707
|
+
const { from, to } = view.state.selection;
|
|
15708
|
+
pinned = box
|
|
15709
|
+
? { from: node.pos, to: node.pos, node: true, box }
|
|
15710
|
+
: { from, to, node: false, box: rangeBox(from, to) };
|
|
15688
15711
|
open = true;
|
|
15689
|
-
options.onStateChange({ isOpen: true, boundingBox, kind
|
|
15712
|
+
options.onStateChange({ isOpen: true, boundingBox: pinned.box, kind });
|
|
15690
15713
|
};
|
|
15691
15714
|
const refresh = () => {
|
|
15692
15715
|
if (destroyed)
|
|
@@ -15696,16 +15719,17 @@ const createBubbleMenu = (options) => defineExtension({
|
|
|
15696
15719
|
close();
|
|
15697
15720
|
return;
|
|
15698
15721
|
}
|
|
15699
|
-
// Open already: the menu
|
|
15700
|
-
// and its box
|
|
15701
|
-
// so what a host renders from the
|
|
15702
|
-
// from the editor (an image's alt,
|
|
15703
|
-
// disagree. Delayed, the image's menu
|
|
15704
|
-
//
|
|
15705
|
-
//
|
|
15706
|
-
//
|
|
15707
|
-
//
|
|
15708
|
-
//
|
|
15722
|
+
// Open already: the menu answers the selection *now* — its kind
|
|
15723
|
+
// (and, following the selection, its box) changes in the same
|
|
15724
|
+
// transaction the selection did, so what a host renders from the
|
|
15725
|
+
// state and what it reads live from the editor (an image's alt,
|
|
15726
|
+
// an action's enabled) never disagree. Delayed, the image's menu
|
|
15727
|
+
// showed the alt of an image no longer selected alone — empty —
|
|
15728
|
+
// and its image tools disabled, for the delay, before the text's
|
|
15729
|
+
// menu replaced it. The delay is for *opening*: a range passing
|
|
15730
|
+
// through, a drag's intermediate selections, never pop a menu of
|
|
15731
|
+
// their own. Pinned (`anchor: 'first'`), the box stays where the
|
|
15732
|
+
// menu opened.
|
|
15709
15733
|
if (open)
|
|
15710
15734
|
return show();
|
|
15711
15735
|
showTimer = setTimeout(show, options.updateDelay ?? 150);
|
|
@@ -15742,7 +15766,7 @@ const createBubbleMenu = (options) => defineExtension({
|
|
|
15742
15766
|
close,
|
|
15743
15767
|
refresh: () => {
|
|
15744
15768
|
if (open)
|
|
15745
|
-
show();
|
|
15769
|
+
show(true);
|
|
15746
15770
|
},
|
|
15747
15771
|
});
|
|
15748
15772
|
return {
|