@jsenv/dom 0.17.27 → 0.17.29
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/jsenv_dom.js +103 -35
- package/package.json +1 -1
package/dist/jsenv_dom.js
CHANGED
|
@@ -2702,6 +2702,12 @@ const normalizeStyle = (
|
|
|
2702
2702
|
|
|
2703
2703
|
if (colorPropertySet.has(propertyName)) {
|
|
2704
2704
|
if (typeof value === "string") {
|
|
2705
|
+
if (context === "css") {
|
|
2706
|
+
// A string is already what the DOM takes, and it takes more of them
|
|
2707
|
+
// (system colors, relative color syntax) than this parser knows;
|
|
2708
|
+
// parsing it to rgba and back would only cost.
|
|
2709
|
+
return value;
|
|
2710
|
+
}
|
|
2705
2711
|
if (isCSSKeyword(value)) {
|
|
2706
2712
|
return value;
|
|
2707
2713
|
}
|
|
@@ -9478,7 +9484,9 @@ const css$4 = /* css */`
|
|
|
9478
9484
|
touch-action: pinch-zoom;
|
|
9479
9485
|
}
|
|
9480
9486
|
[data-drag-ignore],
|
|
9481
|
-
[data-own-target]
|
|
9487
|
+
[data-own-target],
|
|
9488
|
+
[data-drag-source] [popover],
|
|
9489
|
+
[data-drag-source] dialog {
|
|
9482
9490
|
-webkit-touch-callout: default;
|
|
9483
9491
|
touch-action: auto;
|
|
9484
9492
|
}
|
|
@@ -11920,7 +11928,8 @@ const css$1 = /* css */`
|
|
|
11920
11928
|
whoever puts the drag there asks for the hand when a grab really is the
|
|
11921
11929
|
first thing the element offers.
|
|
11922
11930
|
An opted-out area keeps both its cursor and its selection, and never starts
|
|
11923
|
-
a drag (see the check in startDragTo)
|
|
11931
|
+
a drag (see the check in startDragTo); a popover or a dialog anchored in a
|
|
11932
|
+
source is one without having to say so.
|
|
11924
11933
|
Controls inside a source keep their own cursor: cursor is inherited, and
|
|
11925
11934
|
anything setting its own (a button's pointer) wins on itself.
|
|
11926
11935
|
Only the resting cursor is set here: what it becomes once a drag is under
|
|
@@ -11933,7 +11942,9 @@ const css$1 = /* css */`
|
|
|
11933
11942
|
cursor: default;
|
|
11934
11943
|
}
|
|
11935
11944
|
[data-drag-ignore],
|
|
11936
|
-
[data-own-target]
|
|
11945
|
+
[data-own-target],
|
|
11946
|
+
[data-drag-source] [popover],
|
|
11947
|
+
[data-drag-source] dialog {
|
|
11937
11948
|
cursor: auto;
|
|
11938
11949
|
}
|
|
11939
11950
|
|
|
@@ -12033,8 +12044,12 @@ import.meta.css = [css$1, "@jsenv/dom/src/interaction/drag/drag_to.js"];
|
|
|
12033
12044
|
// control that reads the pointer itself. `data-own-target` is the same fact said
|
|
12034
12045
|
// once for every gesture there is: an element declaring that a press landing on
|
|
12035
12046
|
// it is aimed AT it, whatever it happens to sit inside (see also
|
|
12036
|
-
// DRAG_EXCLUDED_SELECTOR in drag_to_travel.js).
|
|
12037
|
-
|
|
12047
|
+
// DRAG_EXCLUDED_SELECTOR in drag_to_travel.js). A popover or a dialog says it
|
|
12048
|
+
// without being asked: it is a layer OVER the surface, so a press in it is aimed
|
|
12049
|
+
// at the layer — yet it stays a descendant of whatever it is anchored in (a
|
|
12050
|
+
// callout next to a button, in the card that carries both), and the press
|
|
12051
|
+
// bubbles through the surface as if it had landed on it.
|
|
12052
|
+
const DRAG_IGNORED_SELECTOR = "[data-drag-ignore],[data-own-target],[popover],dialog";
|
|
12038
12053
|
|
|
12039
12054
|
/**
|
|
12040
12055
|
* Starts a drag-to-reorder interaction on a list item.
|
|
@@ -12534,8 +12549,8 @@ const startDragTo = (event, effects, {
|
|
|
12534
12549
|
...options
|
|
12535
12550
|
} = {}) => {
|
|
12536
12551
|
// An area that opted out of dragging (a text one wants to select, a control that
|
|
12537
|
-
// owns the gesture): the press there is none of our business.
|
|
12538
|
-
if (event.target
|
|
12552
|
+
// owns the gesture, a callout): the press there is none of our business.
|
|
12553
|
+
if (isPressIgnored(event.target, draggedElement)) {
|
|
12539
12554
|
return undefined;
|
|
12540
12555
|
}
|
|
12541
12556
|
// A secondary button (right click and friends) is a context menu, not a grab.
|
|
@@ -12716,8 +12731,8 @@ const startDragToCarryCopy = (event, {
|
|
|
12716
12731
|
...options
|
|
12717
12732
|
}) => {
|
|
12718
12733
|
// An area that opted out of dragging (a text one wants to select, a control
|
|
12719
|
-
// that owns the gesture): the press there is none of our business.
|
|
12720
|
-
if (event.target
|
|
12734
|
+
// that owns the gesture, a callout): the press there is none of our business.
|
|
12735
|
+
if (isPressIgnored(event.target, draggedElement)) {
|
|
12721
12736
|
return undefined;
|
|
12722
12737
|
}
|
|
12723
12738
|
// A secondary button (right click and friends) is a context menu, not a grab.
|
|
@@ -13225,6 +13240,18 @@ const createDragClone = (element, pointerEvent) => {
|
|
|
13225
13240
|
return wrapper;
|
|
13226
13241
|
};
|
|
13227
13242
|
|
|
13243
|
+
// The nearest word about the press wins: an opted-out area INSIDE the dragged
|
|
13244
|
+
// element takes the press away from it, one AROUND it does not — a list
|
|
13245
|
+
// reordered inside a dialog, or a dialog carried by its own handle, is itself the
|
|
13246
|
+
// last thing said before the finger.
|
|
13247
|
+
const isPressIgnored = (target, draggedElement) => {
|
|
13248
|
+
if (!target.closest) {
|
|
13249
|
+
return false;
|
|
13250
|
+
}
|
|
13251
|
+
const ignored = target.closest(DRAG_IGNORED_SELECTOR);
|
|
13252
|
+
return Boolean(ignored) && !ignored.contains(draggedElement);
|
|
13253
|
+
};
|
|
13254
|
+
|
|
13228
13255
|
const startDragToResizeGesture = (
|
|
13229
13256
|
pointerdownEvent,
|
|
13230
13257
|
{ onDragStart, onDrag, onRelease, ...options },
|
|
@@ -13465,8 +13492,10 @@ const DRAG_RESISTANCE = 0.3;
|
|
|
13465
13492
|
// place whose only purpose is to be taken hold of, from the first pixel. And so
|
|
13466
13493
|
// is an OWN TARGET: an element saying a press landing on it is aimed at IT,
|
|
13467
13494
|
// which is the same sentence said to every gesture at once rather than to this
|
|
13468
|
-
// one (see DRAG_IGNORED_SELECTOR in drag_to.js).
|
|
13469
|
-
|
|
13495
|
+
// one (see DRAG_IGNORED_SELECTOR in drag_to.js). And so is a popover or a
|
|
13496
|
+
// dialog: a layer OVER the box, whose press only bubbles through the box because
|
|
13497
|
+
// the layer is anchored in it.
|
|
13498
|
+
const DRAG_EXCLUDED_SELECTOR = ["input", "textarea", "select", '[contenteditable=""]', '[contenteditable="true"]', "[data-drag-handle]", "[data-no-drag-travel]", "[data-own-target]", "[popover]", "dialog"].join(",");
|
|
13470
13499
|
|
|
13471
13500
|
// Which axes a box travels on, one attribute per gesture, said in the DOM by
|
|
13472
13501
|
// whoever owns the box: it is what a box ABOVE another reads to know the
|
|
@@ -13692,7 +13721,7 @@ const startDragToTravel = (pointerDownEvent, {
|
|
|
13692
13721
|
onGiveUp = () => {}
|
|
13693
13722
|
}) => {
|
|
13694
13723
|
const target = pointerDownEvent.target;
|
|
13695
|
-
if (!target.closest || target
|
|
13724
|
+
if (!target.closest || isPressExcluded(target, element)) {
|
|
13696
13725
|
return null;
|
|
13697
13726
|
}
|
|
13698
13727
|
// A box between the finger and this one that travels the same way, and then
|
|
@@ -14153,7 +14182,7 @@ const watchWheelTravel = (element, {
|
|
|
14153
14182
|
const {
|
|
14154
14183
|
target
|
|
14155
14184
|
} = wheelEvent;
|
|
14156
|
-
if (target.closest && target
|
|
14185
|
+
if (target.closest && isPressExcluded(target, element) || scrollRoomTowards(target, element, axis, sign) ||
|
|
14157
14186
|
// …plus the third: a box below this one that travels on this axis. Its
|
|
14158
14187
|
// watcher hears the same wheel event this one does — they all listen at
|
|
14159
14188
|
// the document — so without this both step, and one push moves two
|
|
@@ -14244,6 +14273,14 @@ const watchWheelTravel = (element, {
|
|
|
14244
14273
|
};
|
|
14245
14274
|
};
|
|
14246
14275
|
|
|
14276
|
+
// The nearest word wins: what is excluded INSIDE the box takes the press away
|
|
14277
|
+
// from it, what is around the box does not — a docked dialog IS the box that
|
|
14278
|
+
// travels, and being a dialog is no reason for it to refuse its own press.
|
|
14279
|
+
const isPressExcluded = (target, element) => {
|
|
14280
|
+
const excluded = target.closest(DRAG_EXCLUDED_SELECTOR);
|
|
14281
|
+
return Boolean(excluded) && !excluded.contains(element);
|
|
14282
|
+
};
|
|
14283
|
+
|
|
14247
14284
|
// Shared by navi's own use_displayed_layout_effect.js (rich "navi_displayed"
|
|
14248
14285
|
// CustomEvent, open transitions only) and visible_rect.js (needs both
|
|
14249
14286
|
// directions: hide when a container closes, recheck when it reopens) — the
|
|
@@ -19720,14 +19757,22 @@ const getMaxWidth = (
|
|
|
19720
19757
|
* Summing their `width` values therefore over-counts the true line width.
|
|
19721
19758
|
*
|
|
19722
19759
|
* Instead we compute the bounding extent per line: track the minimum `left`
|
|
19723
|
-
* and maximum `right` across all rects
|
|
19724
|
-
*
|
|
19760
|
+
* and maximum `right` across all rects of the same line, then use
|
|
19761
|
+
* `right - left` as the line width. This is correct regardless of nesting
|
|
19725
19762
|
* depth and works well for regular inline text content.
|
|
19726
19763
|
*
|
|
19727
|
-
*
|
|
19728
|
-
*
|
|
19729
|
-
*
|
|
19730
|
-
*
|
|
19764
|
+
* ## Implementation note — lines are found by vertical overlap
|
|
19765
|
+
*
|
|
19766
|
+
* Boxes sharing a line do not share a `top`: an inline icon sized to 1em and
|
|
19767
|
+
* sitting on the baseline, a superscript, an inline-block, all start a pixel
|
|
19768
|
+
* or a fraction of one away from the text beside them (and that fraction
|
|
19769
|
+
* moves with a sub-pixel scroll offset). Grouping rects by their rounded
|
|
19770
|
+
* `top` would count such a box as a line of its own, and the "longest line"
|
|
19771
|
+
* would come out as the text without it — short enough to make it wrap once
|
|
19772
|
+
* applied as a width. A rect therefore joins the line it overlaps vertically
|
|
19773
|
+
* by more than half the smaller of the two heights: boxes on one line share
|
|
19774
|
+
* most of their height, while the text rects of two consecutive lines overlap
|
|
19775
|
+
* by a sliver at most (a line-height below the font's content height).
|
|
19731
19776
|
*
|
|
19732
19777
|
* Limitation: `range.getClientRects()` returns rects for text nodes and inline
|
|
19733
19778
|
* boxes as laid out in the flow, ignoring any `overflow: hidden` or `max-width`
|
|
@@ -19745,31 +19790,41 @@ const measureLongestVisualLineWidth = (el) => {
|
|
|
19745
19790
|
const range = document.createRange();
|
|
19746
19791
|
range.selectNodeContents(el);
|
|
19747
19792
|
|
|
19748
|
-
const
|
|
19749
|
-
for (const
|
|
19750
|
-
if (
|
|
19793
|
+
const lines = [];
|
|
19794
|
+
for (const rect of range.getClientRects()) {
|
|
19795
|
+
if (rect.width === 0) {
|
|
19751
19796
|
continue;
|
|
19752
19797
|
}
|
|
19753
|
-
const
|
|
19754
|
-
|
|
19755
|
-
|
|
19756
|
-
|
|
19757
|
-
|
|
19758
|
-
|
|
19759
|
-
|
|
19760
|
-
}
|
|
19761
|
-
|
|
19762
|
-
|
|
19763
|
-
|
|
19798
|
+
const line = lines.find((candidate) => sharesLine(candidate, rect));
|
|
19799
|
+
if (line === undefined) {
|
|
19800
|
+
lines.push({
|
|
19801
|
+
top: rect.top,
|
|
19802
|
+
bottom: rect.bottom,
|
|
19803
|
+
left: rect.left,
|
|
19804
|
+
right: rect.right,
|
|
19805
|
+
});
|
|
19806
|
+
continue;
|
|
19807
|
+
}
|
|
19808
|
+
if (rect.top < line.top) {
|
|
19809
|
+
line.top = rect.top;
|
|
19810
|
+
}
|
|
19811
|
+
if (rect.bottom > line.bottom) {
|
|
19812
|
+
line.bottom = rect.bottom;
|
|
19813
|
+
}
|
|
19814
|
+
if (rect.left < line.left) {
|
|
19815
|
+
line.left = rect.left;
|
|
19816
|
+
}
|
|
19817
|
+
if (rect.right > line.right) {
|
|
19818
|
+
line.right = rect.right;
|
|
19764
19819
|
}
|
|
19765
19820
|
}
|
|
19766
19821
|
|
|
19767
|
-
if (
|
|
19822
|
+
if (lines.length <= 1) {
|
|
19768
19823
|
return null;
|
|
19769
19824
|
}
|
|
19770
19825
|
|
|
19771
19826
|
let longestLineWidth = 0;
|
|
19772
|
-
for (const { left, right } of
|
|
19827
|
+
for (const { left, right } of lines) {
|
|
19773
19828
|
const w = right - left;
|
|
19774
19829
|
if (w > longestLineWidth) {
|
|
19775
19830
|
longestLineWidth = w;
|
|
@@ -19778,6 +19833,19 @@ const measureLongestVisualLineWidth = (el) => {
|
|
|
19778
19833
|
return longestLineWidth;
|
|
19779
19834
|
};
|
|
19780
19835
|
|
|
19836
|
+
const sharesLine = (line, rect) => {
|
|
19837
|
+
const overlapTop = rect.top > line.top ? rect.top : line.top;
|
|
19838
|
+
const overlapBottom = rect.bottom < line.bottom ? rect.bottom : line.bottom;
|
|
19839
|
+
const overlap = overlapBottom - overlapTop;
|
|
19840
|
+
if (overlap <= 0) {
|
|
19841
|
+
return false;
|
|
19842
|
+
}
|
|
19843
|
+
const rectHeight = rect.bottom - rect.top;
|
|
19844
|
+
const lineHeight = line.bottom - line.top;
|
|
19845
|
+
const smallerHeight = rectHeight < lineHeight ? rectHeight : lineHeight;
|
|
19846
|
+
return overlap > smallerHeight / 2;
|
|
19847
|
+
};
|
|
19848
|
+
|
|
19781
19849
|
// Measures the width of the widest row of direct children.
|
|
19782
19850
|
// Uses children's bounding rects (which respect overflow:hidden / max-width)
|
|
19783
19851
|
// rather than Range.getClientRects() which sees through clipping boundaries.
|