@jsenv/dom 0.17.45 → 0.17.47
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 +288 -147
- package/package.json +6 -2
package/dist/jsenv_dom.js
CHANGED
|
@@ -4524,15 +4524,31 @@ const waitForPressHeld = (
|
|
|
4524
4524
|
}
|
|
4525
4525
|
cancelPress(pointerEndEvent);
|
|
4526
4526
|
};
|
|
4527
|
+
// Somebody else settled what this press is. Taking the pointer is how a gesture
|
|
4528
|
+
// says it — and it says it about the same finger this wait is counting on, so
|
|
4529
|
+
// whatever the press turned out to be, it is not a hold. Two waits on one press
|
|
4530
|
+
// is the ordinary case rather than an odd one: an element that can be picked up
|
|
4531
|
+
// AND held answers a finger with two delays, the shorter one wins, and without
|
|
4532
|
+
// this the longer one would answer a hundred milliseconds into the carry.
|
|
4533
|
+
// The listener goes with the countdown, so the gesture THIS wait starts (which
|
|
4534
|
+
// captures the pointer from inside onPressHeld) never reaches it.
|
|
4535
|
+
const onGotPointerCapture = (captureEvent) => {
|
|
4536
|
+
if (captureEvent.pointerId !== pointerId) {
|
|
4537
|
+
return;
|
|
4538
|
+
}
|
|
4539
|
+
cancelPress(captureEvent);
|
|
4540
|
+
};
|
|
4527
4541
|
// On window rather than on the element: the finger can leave it, and the
|
|
4528
4542
|
// element itself can be taken out of the document while the press is waiting.
|
|
4529
4543
|
window.addEventListener("pointermove", onPointerMove);
|
|
4530
4544
|
window.addEventListener("pointerup", onPointerEnd);
|
|
4531
4545
|
window.addEventListener("pointercancel", onPointerEnd);
|
|
4546
|
+
window.addEventListener("gotpointercapture", onGotPointerCapture, true);
|
|
4532
4547
|
countdownCleanupCallbacks.push(() => {
|
|
4533
4548
|
window.removeEventListener("pointermove", onPointerMove);
|
|
4534
4549
|
window.removeEventListener("pointerup", onPointerEnd);
|
|
4535
4550
|
window.removeEventListener("pointercancel", onPointerEnd);
|
|
4551
|
+
window.removeEventListener("gotpointercapture", onGotPointerCapture, true);
|
|
4536
4552
|
});
|
|
4537
4553
|
|
|
4538
4554
|
onPressStart?.(pressEvent);
|
|
@@ -7515,7 +7531,8 @@ const getScrollbarState = (
|
|
|
7515
7531
|
* scrollIntoViewScoped avoids this by targeting one container explicitly.
|
|
7516
7532
|
*
|
|
7517
7533
|
* Uses scrollTo() so CSS scroll-behavior:smooth on the container is respected.
|
|
7518
|
-
* Respects scroll-margin-* on the element
|
|
7534
|
+
* Respects scroll-margin-* on the element and scroll-padding-* on the
|
|
7535
|
+
* container.
|
|
7519
7536
|
*
|
|
7520
7537
|
* @param {Element} el - The element to scroll into view.
|
|
7521
7538
|
* @param {object} options
|
|
@@ -7621,6 +7638,31 @@ const getScrollIntoViewScopedOffsets = (
|
|
|
7621
7638
|
containerWidth = containerRect.width;
|
|
7622
7639
|
}
|
|
7623
7640
|
|
|
7641
|
+
// The band the container keeps free at each of its edges for whatever is
|
|
7642
|
+
// scrolled to — what a sticky header, a footer or a fixed bar reserves so an
|
|
7643
|
+
// element does not land underneath it (see navi's safe_area.js). The
|
|
7644
|
+
// scrollport shrinks by it on both axes, and every alignment below is against
|
|
7645
|
+
// that smaller rectangle.
|
|
7646
|
+
const containerStyle = getComputedStyle(container);
|
|
7647
|
+
const scrollPaddingTop = resolveScrollPadding(
|
|
7648
|
+
containerStyle.scrollPaddingTop,
|
|
7649
|
+
containerHeight,
|
|
7650
|
+
);
|
|
7651
|
+
const scrollPaddingBottom = resolveScrollPadding(
|
|
7652
|
+
containerStyle.scrollPaddingBottom,
|
|
7653
|
+
containerHeight,
|
|
7654
|
+
);
|
|
7655
|
+
const scrollPaddingLeft = resolveScrollPadding(
|
|
7656
|
+
containerStyle.scrollPaddingLeft,
|
|
7657
|
+
containerWidth,
|
|
7658
|
+
);
|
|
7659
|
+
const scrollPaddingRight = resolveScrollPadding(
|
|
7660
|
+
containerStyle.scrollPaddingRight,
|
|
7661
|
+
containerWidth,
|
|
7662
|
+
);
|
|
7663
|
+
const viewHeight = containerHeight - scrollPaddingTop - scrollPaddingBottom;
|
|
7664
|
+
const viewWidth = containerWidth - scrollPaddingLeft - scrollPaddingRight;
|
|
7665
|
+
|
|
7624
7666
|
// Element position relative to the container's scroll origin.
|
|
7625
7667
|
const elTop = elRect.top - containerTop + currentScrollTop - scrollMarginTop;
|
|
7626
7668
|
const elBottom = elTop + elRect.height + scrollMarginTop + scrollMarginBottom;
|
|
@@ -7628,55 +7670,67 @@ const getScrollIntoViewScopedOffsets = (
|
|
|
7628
7670
|
elRect.left - containerLeft + currentScrollLeft - scrollMarginLeft;
|
|
7629
7671
|
const elRight = elLeft + elRect.width + scrollMarginLeft + scrollMarginRight;
|
|
7630
7672
|
|
|
7673
|
+
// The two scroll positions that put the element against one edge of the view
|
|
7674
|
+
// or the other — every alignment below is one of them, or a point between.
|
|
7675
|
+
const scrollTopPuttingElAtViewStart = elTop - scrollPaddingTop;
|
|
7676
|
+
const scrollTopPuttingElAtViewEnd =
|
|
7677
|
+
elBottom - containerHeight + scrollPaddingBottom;
|
|
7678
|
+
const viewStart = currentScrollTop + scrollPaddingTop;
|
|
7679
|
+
const viewEnd = currentScrollTop + containerHeight - scrollPaddingBottom;
|
|
7680
|
+
|
|
7631
7681
|
let newScrollTop = currentScrollTop;
|
|
7632
7682
|
if (block === "start") {
|
|
7633
|
-
newScrollTop =
|
|
7683
|
+
newScrollTop = scrollTopPuttingElAtViewStart;
|
|
7634
7684
|
} else if (block === "end") {
|
|
7635
|
-
newScrollTop =
|
|
7685
|
+
newScrollTop = scrollTopPuttingElAtViewEnd;
|
|
7636
7686
|
} else if (block === "center") {
|
|
7637
|
-
newScrollTop = elTop + (elRect.height -
|
|
7687
|
+
newScrollTop = elTop + (elRect.height - viewHeight) / 2 - scrollPaddingTop;
|
|
7638
7688
|
} else {
|
|
7639
7689
|
// nearest: scroll only if partially or fully out of view.
|
|
7640
|
-
// When the element is taller than the
|
|
7690
|
+
// When the element is taller than the view, only scroll if it is
|
|
7641
7691
|
// completely out of view — otherwise it is already as visible as possible.
|
|
7642
|
-
const scrollBottom = currentScrollTop + containerHeight;
|
|
7643
7692
|
const elHeight = elBottom - elTop;
|
|
7644
|
-
if (elHeight <=
|
|
7645
|
-
if (elTop <
|
|
7646
|
-
newScrollTop =
|
|
7647
|
-
} else if (elBottom >
|
|
7648
|
-
newScrollTop =
|
|
7693
|
+
if (elHeight <= viewHeight) {
|
|
7694
|
+
if (elTop < viewStart) {
|
|
7695
|
+
newScrollTop = scrollTopPuttingElAtViewStart;
|
|
7696
|
+
} else if (elBottom > viewEnd) {
|
|
7697
|
+
newScrollTop = scrollTopPuttingElAtViewEnd;
|
|
7649
7698
|
}
|
|
7650
|
-
} else if (elBottom <
|
|
7651
|
-
newScrollTop =
|
|
7652
|
-
} else if (elTop >
|
|
7653
|
-
newScrollTop =
|
|
7699
|
+
} else if (elBottom < viewStart) {
|
|
7700
|
+
newScrollTop = scrollTopPuttingElAtViewEnd;
|
|
7701
|
+
} else if (elTop > viewEnd) {
|
|
7702
|
+
newScrollTop = scrollTopPuttingElAtViewStart;
|
|
7654
7703
|
}
|
|
7655
7704
|
}
|
|
7656
7705
|
|
|
7706
|
+
const scrollLeftPuttingElAtViewStart = elLeft - scrollPaddingLeft;
|
|
7707
|
+
const scrollLeftPuttingElAtViewEnd =
|
|
7708
|
+
elRight - containerWidth + scrollPaddingRight;
|
|
7709
|
+
const viewLeftEdge = currentScrollLeft + scrollPaddingLeft;
|
|
7710
|
+
const viewRightEdge = currentScrollLeft + containerWidth - scrollPaddingRight;
|
|
7711
|
+
|
|
7657
7712
|
let newScrollLeft = currentScrollLeft;
|
|
7658
7713
|
if (inline === "start") {
|
|
7659
|
-
newScrollLeft =
|
|
7714
|
+
newScrollLeft = scrollLeftPuttingElAtViewStart;
|
|
7660
7715
|
} else if (inline === "end") {
|
|
7661
|
-
newScrollLeft =
|
|
7716
|
+
newScrollLeft = scrollLeftPuttingElAtViewEnd;
|
|
7662
7717
|
} else if (inline === "center") {
|
|
7663
|
-
newScrollLeft = elLeft + (elRect.width -
|
|
7718
|
+
newScrollLeft = elLeft + (elRect.width - viewWidth) / 2 - scrollPaddingLeft;
|
|
7664
7719
|
} else {
|
|
7665
7720
|
// nearest: scroll only if partially or fully out of view.
|
|
7666
|
-
// When the element is wider than the
|
|
7721
|
+
// When the element is wider than the view, only scroll if it is
|
|
7667
7722
|
// completely out of view — otherwise it is already as visible as possible.
|
|
7668
|
-
const scrollRight = currentScrollLeft + containerWidth;
|
|
7669
7723
|
const elWidth = elRight - elLeft;
|
|
7670
|
-
if (elWidth <=
|
|
7671
|
-
if (elLeft <
|
|
7672
|
-
newScrollLeft =
|
|
7673
|
-
} else if (elRight >
|
|
7674
|
-
newScrollLeft =
|
|
7724
|
+
if (elWidth <= viewWidth) {
|
|
7725
|
+
if (elLeft < viewLeftEdge) {
|
|
7726
|
+
newScrollLeft = scrollLeftPuttingElAtViewStart;
|
|
7727
|
+
} else if (elRight > viewRightEdge) {
|
|
7728
|
+
newScrollLeft = scrollLeftPuttingElAtViewEnd;
|
|
7675
7729
|
}
|
|
7676
|
-
} else if (elRight <
|
|
7677
|
-
newScrollLeft =
|
|
7678
|
-
} else if (elLeft >
|
|
7679
|
-
newScrollLeft =
|
|
7730
|
+
} else if (elRight < viewLeftEdge) {
|
|
7731
|
+
newScrollLeft = scrollLeftPuttingElAtViewEnd;
|
|
7732
|
+
} else if (elLeft > viewRightEdge) {
|
|
7733
|
+
newScrollLeft = scrollLeftPuttingElAtViewStart;
|
|
7680
7734
|
}
|
|
7681
7735
|
}
|
|
7682
7736
|
|
|
@@ -7686,6 +7740,20 @@ const getScrollIntoViewScopedOffsets = (
|
|
|
7686
7740
|
};
|
|
7687
7741
|
};
|
|
7688
7742
|
|
|
7743
|
+
// "auto" is the one keyword scroll-padding takes, and it means "the browser
|
|
7744
|
+
// picks" — which is 0 everywhere in practice. Percentages resolve against the
|
|
7745
|
+
// scrollport, and getComputedStyle hands them back as written.
|
|
7746
|
+
const resolveScrollPadding = (value, scrollportSize) => {
|
|
7747
|
+
const number = parseFloat(value);
|
|
7748
|
+
if (Number.isNaN(number)) {
|
|
7749
|
+
return 0;
|
|
7750
|
+
}
|
|
7751
|
+
if (value.endsWith("%")) {
|
|
7752
|
+
return (number / 100) * scrollportSize;
|
|
7753
|
+
}
|
|
7754
|
+
return number;
|
|
7755
|
+
};
|
|
7756
|
+
|
|
7689
7757
|
/**
|
|
7690
7758
|
* DON'T USE THIS, use scroll-padding-top/bottom in CSS instead
|
|
7691
7759
|
* better in every aspect
|
|
@@ -9978,6 +10046,13 @@ const createDragElementPositioner = (
|
|
|
9978
10046
|
// returns null (document.documentElement instead — see its own doc).
|
|
9979
10047
|
const positionedParent = getPositionedParent(elementToMove || element);
|
|
9980
10048
|
const scrollContainer = getScrollContainer(element);
|
|
10049
|
+
// Whether what MOVES is pinned to the viewport — a copy carried above the page
|
|
10050
|
+
// in the top layer, a fixed panel dragged by its handle. Such a thing does not
|
|
10051
|
+
// travel with any scroll, so the scroll that happens while it is carried is
|
|
10052
|
+
// none of its business (see getScrollOffsets).
|
|
10053
|
+
const elementMovedIsPinnedToViewport = Boolean(
|
|
10054
|
+
findSelfOrAncestorFixedPosition(elementToMove || element),
|
|
10055
|
+
);
|
|
9981
10056
|
const [getPositionOffsets, getScrollOffsets] = createGetOffsets({
|
|
9982
10057
|
positionedParent,
|
|
9983
10058
|
referencePositionedParent: referenceElement
|
|
@@ -9987,6 +10062,7 @@ const createDragElementPositioner = (
|
|
|
9987
10062
|
referenceScrollContainer: referenceElement
|
|
9988
10063
|
? getScrollContainer(referenceElement)
|
|
9989
10064
|
: scrollContainer,
|
|
10065
|
+
elementMovedIsPinnedToViewport,
|
|
9990
10066
|
});
|
|
9991
10067
|
|
|
9992
10068
|
{
|
|
@@ -10039,6 +10115,7 @@ const createGetOffsets = ({
|
|
|
10039
10115
|
referencePositionedParent,
|
|
10040
10116
|
scrollContainer,
|
|
10041
10117
|
referenceScrollContainer,
|
|
10118
|
+
elementMovedIsPinnedToViewport,
|
|
10042
10119
|
}) => {
|
|
10043
10120
|
const samePositionedParent = positionedParent === referencePositionedParent;
|
|
10044
10121
|
const getScrollOffsets = createGetScrollOffsets(
|
|
@@ -10046,6 +10123,7 @@ const createGetOffsets = ({
|
|
|
10046
10123
|
referenceScrollContainer,
|
|
10047
10124
|
positionedParent,
|
|
10048
10125
|
samePositionedParent,
|
|
10126
|
+
elementMovedIsPinnedToViewport,
|
|
10049
10127
|
);
|
|
10050
10128
|
|
|
10051
10129
|
if (samePositionedParent) {
|
|
@@ -10250,6 +10328,7 @@ const createGetScrollOffsets = (
|
|
|
10250
10328
|
referenceScrollContainer,
|
|
10251
10329
|
positionedParent,
|
|
10252
10330
|
samePositionedParent,
|
|
10331
|
+
elementMovedIsPinnedToViewport,
|
|
10253
10332
|
) => {
|
|
10254
10333
|
const getGetScrollOffsetsSameContainer = () => {
|
|
10255
10334
|
const scrollContainerIsDocument = scrollContainer === documentElement;
|
|
@@ -10271,9 +10350,14 @@ const createGetScrollOffsets = (
|
|
|
10271
10350
|
return getScrollOffsetsFixed;
|
|
10272
10351
|
}
|
|
10273
10352
|
}
|
|
10353
|
+
// A thing pinned to the viewport is inside nothing that scrolls: the page
|
|
10354
|
+
// can run under it and it stays where it is. So it takes the frozen offset
|
|
10355
|
+
// below whatever containment says — and the document, as a scroll container,
|
|
10356
|
+
// answers "yes, it is inside me" to everything.
|
|
10274
10357
|
const positionedParentIsInsideScrollContainer =
|
|
10275
|
-
|
|
10276
|
-
referenceScrollContainer
|
|
10358
|
+
!elementMovedIsPinnedToViewport &&
|
|
10359
|
+
(referenceScrollContainer === documentElement ||
|
|
10360
|
+
referenceScrollContainer.contains(positionedParent));
|
|
10277
10361
|
if (!positionedParentIsInsideScrollContainer) {
|
|
10278
10362
|
// positionedParent is outside the scroll container (e.g. clone in document.body
|
|
10279
10363
|
// while tracking an element inside a custom scroll container).
|
|
@@ -12066,6 +12150,7 @@ const css$1 = /* css */ `.navi_drop_hint {
|
|
|
12066
12150
|
transform: scale(var(--drag-clone-scale, 1.03));
|
|
12067
12151
|
transform-origin: var(--drag-origin);
|
|
12068
12152
|
transition: transform .15s cubic-bezier(.34, 1.56, .64, 1), box-shadow .15s;
|
|
12153
|
+
translate: none !important;
|
|
12069
12154
|
}
|
|
12070
12155
|
|
|
12071
12156
|
@starting-style {
|
|
@@ -12096,90 +12181,6 @@ import.meta.css = [css$1, "@jsenv/dom/src/interaction/drag/drag_to.js"];
|
|
|
12096
12181
|
const DRAG_IGNORED_SELECTOR =
|
|
12097
12182
|
'[data-drag-ignore],[data-self-interactions~="drag"],[data-self-interactions~="*"],[popover],dialog';
|
|
12098
12183
|
|
|
12099
|
-
/**
|
|
12100
|
-
* Starts a drag-to-reorder interaction on a list item.
|
|
12101
|
-
*
|
|
12102
|
-
* Handles the full reorder UX:
|
|
12103
|
-
* - Activates only once the intent is established — a short movement with a mouse, a long
|
|
12104
|
-
* press with a finger (see `dragAfterIntent`), so that neither a click nor a scroll
|
|
12105
|
-
* reorders anything by accident.
|
|
12106
|
-
* - Clones the grabbed element and moves the clone while the original stays hidden in place
|
|
12107
|
-
* (keeps the layout intact so other items don't shift during the drag).
|
|
12108
|
-
* - The clone and the drop-hint live in the dragged element's own parent, so the CSS vars
|
|
12109
|
-
* that dress them (`--drag-clone-shadow`, `--drop-hint-size`, …) reach them by plain
|
|
12110
|
-
* inheritance, and so do the rules the list writes for its items.
|
|
12111
|
-
* - Shows a drop-hint line indicating where the item will land.
|
|
12112
|
-
* - Drop-target detection is intersection-based: the clone's bounding rect is compared
|
|
12113
|
-
* against every item that matches `itemSelector` in the scroll container.
|
|
12114
|
-
* - No-ops are filtered: releasing on the grabbed element itself, or in a position that
|
|
12115
|
-
* would leave it at exactly the same index, never triggers `onReorder`.
|
|
12116
|
-
* - On a valid drop, the clone animates to the drop position via the View Transitions API,
|
|
12117
|
-
* `onReorder` is called inside the transition callback so the DOM update and the animation
|
|
12118
|
-
* are captured together, then the clone is removed.
|
|
12119
|
-
* - On a cancelled drop (pointer released with no valid target), the clone is removed
|
|
12120
|
-
* immediately without calling `onReorder`.
|
|
12121
|
-
*
|
|
12122
|
-
* IDs are used as the bridge between DOM elements and JS state because:
|
|
12123
|
-
* - Not all DOM elements matching `itemSelector` may be valid drop targets
|
|
12124
|
-
* (holes in the structure), so DOM indices don't reliably map to state indices.
|
|
12125
|
-
* - Virtual lists render fewer DOM nodes than the total item count, so
|
|
12126
|
-
* DOM-index-based counting would be wrong.
|
|
12127
|
-
*
|
|
12128
|
-
* Any option not listed below is forwarded to `createDragToMoveGestureController`
|
|
12129
|
-
* (`areaConstraint`, `autoScrollAreaPadding`, `stickyFrontiers`…), except
|
|
12130
|
-
* `releasePositionEffect`, always `"manual"` here: what moves is the clone, and it
|
|
12131
|
-
* is removed on release, so there is no position to commit or cancel.
|
|
12132
|
-
*
|
|
12133
|
-
* @param {PointerEvent} event
|
|
12134
|
-
* The `pointerdown` event that may become a reorder.
|
|
12135
|
-
* @param {object} options
|
|
12136
|
-
* @param {Element} [options.draggedElement=event.currentTarget]
|
|
12137
|
-
* The list item to drag.
|
|
12138
|
-
* @param {Element} [options.containerElement=draggedElement.parentElement]
|
|
12139
|
-
* Element searched with `itemSelector` to find the items to drop between.
|
|
12140
|
-
* @param {string} [options.itemSelector]
|
|
12141
|
-
* CSS selector that matches all list items inside `containerElement`.
|
|
12142
|
-
* Used for drop-target detection and no-op filtering. Left out, nothing is a
|
|
12143
|
-
* drop target: no hint is drawn and no reorder can be answered — which is what
|
|
12144
|
-
* a drag that only ever throws the thing away asks for.
|
|
12145
|
-
* @param {function} options.getItemId
|
|
12146
|
-
* Returns the stable ID for a given DOM element.
|
|
12147
|
-
* Signature: `getItemId(element) → id`.
|
|
12148
|
-
* @param {function} options.onReorder
|
|
12149
|
-
* Called when the user drops the item in a new position.
|
|
12150
|
-
* Signature: `onReorder(fromId, toId, syncCloneWithDropTarget)`.
|
|
12151
|
-
* - `fromId`: stable ID of the dragged item.
|
|
12152
|
-
* - `toId`: stable ID of the item to insert before, or `null` to append at the end.
|
|
12153
|
-
* - `syncCloneWithDropTarget`: call it synchronously inside a
|
|
12154
|
-
* `document.startViewTransition` callback, next to the DOM mutation, so the
|
|
12155
|
-
* clone is captured at its landing position.
|
|
12156
|
-
* @param {(detail: {gestureInfo: object, dropTarget: Element|null}) => "reorder"|"toss"|"cancel"} [options.resolveDrop]
|
|
12157
|
-
* What THIS release means, when the answer is not simply "a target was found or
|
|
12158
|
-
* not": the same grab can be meant to reorder or to get rid of the thing, and
|
|
12159
|
-
* only the caller knows which — far and fast is a throw, over a row is a move.
|
|
12160
|
-
* Left out, a drop target reorders and anything else is cancelled.
|
|
12161
|
-
* @param {(detail: {gestureInfo: object}) => Promise|void} [options.onToss]
|
|
12162
|
-
* The release was a throw. The clone leaves the screen the way it was thrown
|
|
12163
|
-
* while this runs; it comes back if the promise rejects, because the thing still
|
|
12164
|
-
* exists and the screen has to say so.
|
|
12165
|
-
* @param {object} [options.direction={ x: false, y: true }]
|
|
12166
|
-
* Axes along which dragging is allowed. Passed to `createDragToMoveGestureController`.
|
|
12167
|
-
* @param {number} [options.threshold=5]
|
|
12168
|
-
* Distance (px) a mouse must travel before the press becomes a drag.
|
|
12169
|
-
* @param {boolean|"if-touch"} [options.longPress="if-touch"]
|
|
12170
|
-
* Which pointers start the drag by holding still instead of by travelling.
|
|
12171
|
-
* @param {number} [options.longPressDelay=400]
|
|
12172
|
-
* How long (ms) such a pointer must stay down.
|
|
12173
|
-
* @param {number} [options.longPressSlop=8]
|
|
12174
|
-
* How far (px) it may drift during that wait before the press is abandoned.
|
|
12175
|
-
* @param {function} [options.onPressStart]
|
|
12176
|
-
* The pointer went down and the wait began (a cue that the press counts).
|
|
12177
|
-
* @param {function} [options.onPressCancel]
|
|
12178
|
-
* The pointer moved or lifted before the wait was over.
|
|
12179
|
-
* @param {function} [options.onPress]
|
|
12180
|
-
* The wait completed and the item is now held (haptics, scale…).
|
|
12181
|
-
*/
|
|
12182
|
-
|
|
12183
12184
|
/**
|
|
12184
12185
|
* Creates a gesture controller that moves elements via drag.
|
|
12185
12186
|
*
|
|
@@ -12588,25 +12589,43 @@ const createDragToMoveGestureController = ({
|
|
|
12588
12589
|
* It was put somewhere. The position is already committed when this runs — the
|
|
12589
12590
|
* hand let go of it there — and travels back if the promise rejects.
|
|
12590
12591
|
* @param {Element} [options.containerElement=draggedElement.parentElement]
|
|
12591
|
-
*
|
|
12592
|
+
* Where the places are looked for with `itemSelector`, and where the drop hint
|
|
12593
|
+
* is drawn. The parent covers a list and a board, whose items are siblings of
|
|
12594
|
+
* what is carried; anything else has to be said — a palette beside the surface
|
|
12595
|
+
* it fills, a piece drawn INSIDE the place it can be put back on.
|
|
12592
12596
|
* @param {string} [options.itemSelector] What matches the items of the list.
|
|
12593
|
-
*
|
|
12597
|
+
* Left out, nothing is a place: no hint is drawn and no landing can be
|
|
12598
|
+
* answered, which is what a drag that only ever throws the thing away asks for.
|
|
12599
|
+
* @param {function} [options.getItemId] `getItemId(element) → id`. An id rather
|
|
12600
|
+
* than a DOM index, because the two do not match: a list draws fewer rows than
|
|
12601
|
+
* it has, a search reorders them, and the structure may have holes.
|
|
12594
12602
|
* @param {function} [options.onReorder]
|
|
12595
12603
|
* `onReorder(fromId, toId, syncCloneWithDropTarget)` — see its own note below.
|
|
12596
12604
|
* @param {(detail: {gestureInfo: object}) => Promise|void} [options.onToss]
|
|
12597
12605
|
* It was thrown away. The copy leaves the screen while this runs and comes back
|
|
12598
12606
|
* if the promise rejects, because the thing still exists and the screen has to
|
|
12599
12607
|
* say so.
|
|
12600
|
-
* @param {
|
|
12601
|
-
*
|
|
12602
|
-
* is
|
|
12603
|
-
*
|
|
12604
|
-
*
|
|
12605
|
-
*
|
|
12608
|
+
* @param {(detail: {fromId: string, toId: string, x: number, y: number, width: number, height: number, syncCloneWithDropTarget: Function}) => Promise|void} [options.onLand]
|
|
12609
|
+
* It came down on `toId`, which is an element and never null: nothing under the
|
|
12610
|
+
* copy is a cancelled release. `x`/`y`/`width`/`height` say WHERE on it, which
|
|
12611
|
+
* is the whole answer when the place is a surface — a plan, a map — with no
|
|
12612
|
+
* element under the copy to name. The copy is held until what comes back
|
|
12613
|
+
* settles, exactly like `onReorder`. `syncCloneWithDropTarget` takes an element
|
|
12614
|
+
* when the place is not the shape of what stands on it: the copy then takes
|
|
12615
|
+
* THAT box instead of the target's.
|
|
12606
12616
|
* @param {number} [options.tossDistance=110] How far a throw goes, in px.
|
|
12607
12617
|
* @param {number} [options.tossSpeed=0.45] And how fast, in px/ms. BOTH are asked
|
|
12608
12618
|
* for: one without the other is moving the thing while hesitating, and nothing is
|
|
12609
12619
|
* thrown away on a hesitation.
|
|
12620
|
+
* @param {("throw"|"release-outside")[]} [options.tossBy=["throw"]] How a toss
|
|
12621
|
+
* is made here. A THROW is far and fast — the flick that gets rid of something,
|
|
12622
|
+
* a list's gesture, judged before any landing. A RELEASE OUTSIDE has no place
|
|
12623
|
+
* under it — dragging something off the surface it belongs to and letting go,
|
|
12624
|
+
* deliberate and never a flick, a surface's gesture. Each is asked for on its
|
|
12625
|
+
* own: a surface wants only the second (a fast drag across it that ends ON it
|
|
12626
|
+
* has not asked for the thing to go), a list only the first (a row let go of
|
|
12627
|
+
* beside its list is a row put back). With no place to be outside of (no
|
|
12628
|
+
* `itemSelector`), every release is outside.
|
|
12610
12629
|
*
|
|
12611
12630
|
* Everything else is forwarded to `createDragToMoveGestureController`
|
|
12612
12631
|
* (`areaConstraint`, `autoScrollAreaPadding`, `direction`…) and to `dragAfterIntent`
|
|
@@ -12721,6 +12740,8 @@ const startDragToMoveElement = (
|
|
|
12721
12740
|
// hesitating, and nothing is thrown away on a hesitation — it comes back.
|
|
12722
12741
|
const TOSS_DISTANCE_TO_COMMIT = 110;
|
|
12723
12742
|
const TOSS_SPEED_TO_COMMIT = 0.45;
|
|
12743
|
+
// The flick is how a list gets rid of a row; a surface says otherwise.
|
|
12744
|
+
const TOSS_BY_DEFAULT = ["throw"];
|
|
12724
12745
|
|
|
12725
12746
|
const resolveDropMeaning = ({
|
|
12726
12747
|
gestureInfo,
|
|
@@ -12730,6 +12751,7 @@ const resolveDropMeaning = ({
|
|
|
12730
12751
|
canLand,
|
|
12731
12752
|
tossDistance = TOSS_DISTANCE_TO_COMMIT,
|
|
12732
12753
|
tossSpeed = TOSS_SPEED_TO_COMMIT,
|
|
12754
|
+
tossBy = TOSS_BY_DEFAULT,
|
|
12733
12755
|
}) => {
|
|
12734
12756
|
if (gestureInfo.cancelled) {
|
|
12735
12757
|
// Nobody let go of anything: the gesture was taken away mid-air (the
|
|
@@ -12737,7 +12759,7 @@ const resolveDropMeaning = ({
|
|
|
12737
12759
|
// to be at that moment is not a place it was put.
|
|
12738
12760
|
return "cancel";
|
|
12739
12761
|
}
|
|
12740
|
-
if (canToss) {
|
|
12762
|
+
if (canToss && tossBy.includes("throw")) {
|
|
12741
12763
|
const { xDelta, yDelta } = gestureInfo.layout;
|
|
12742
12764
|
const distance = Math.hypot(xDelta, yDelta);
|
|
12743
12765
|
if (distance > tossDistance && gestureInfo.velocity > tossSpeed) {
|
|
@@ -12752,6 +12774,21 @@ const resolveDropMeaning = ({
|
|
|
12752
12774
|
return "reorder";
|
|
12753
12775
|
}
|
|
12754
12776
|
}
|
|
12777
|
+
if (canToss && tossBy.includes("release-outside")) {
|
|
12778
|
+
// Let go of away from every place: the other way of meaning "get rid of
|
|
12779
|
+
// this", and the one a surface asks for — off the plan and down is
|
|
12780
|
+
// deliberate, never a flick.
|
|
12781
|
+
//
|
|
12782
|
+
// "Away from every place" is the last frame's answer, not the one above: a
|
|
12783
|
+
// row let go of where it already was has no place to INSERT it at and still
|
|
12784
|
+
// has a place under it. And it has to have gone somewhere to be away from
|
|
12785
|
+
// anything — picked up and put straight back down is a hand that changed its
|
|
12786
|
+
// mind, not a thing dropped over nothing.
|
|
12787
|
+
const { xDelta, yDelta } = gestureInfo.layout;
|
|
12788
|
+
if ((xDelta || yDelta) && !gestureInfo.dropTargetInfo) {
|
|
12789
|
+
return "toss";
|
|
12790
|
+
}
|
|
12791
|
+
}
|
|
12755
12792
|
return "cancel";
|
|
12756
12793
|
};
|
|
12757
12794
|
|
|
@@ -12788,6 +12825,7 @@ const startDragToCarryCopy = (
|
|
|
12788
12825
|
onToss,
|
|
12789
12826
|
tossDistance,
|
|
12790
12827
|
tossSpeed,
|
|
12828
|
+
tossBy,
|
|
12791
12829
|
// A list runs one way and reordering walks it; a board has places all around,
|
|
12792
12830
|
// so something landing on one of them goes wherever the hand takes it.
|
|
12793
12831
|
direction = canLand ? { x: true, y: true } : { x: false, y: true },
|
|
@@ -12853,10 +12891,12 @@ const startDragToCarryCopy = (
|
|
|
12853
12891
|
? createDropHint()
|
|
12854
12892
|
: null;
|
|
12855
12893
|
if (dropHintEl) {
|
|
12856
|
-
//
|
|
12894
|
+
// Among the places it lights up, which is where its own vars are set: the
|
|
12857
12895
|
// shape of a drop hint is a property of the list or board it belongs to,
|
|
12858
|
-
// and reading it from there is inheritance rather than a hand-off.
|
|
12859
|
-
|
|
12896
|
+
// and reading it from there is inheritance rather than a hand-off. The
|
|
12897
|
+
// copy goes the other way (see createDragClone) — it is dressed by where
|
|
12898
|
+
// the thing it copies stands, which may be a palette far from here.
|
|
12899
|
+
containerElement.appendChild(dropHintEl);
|
|
12860
12900
|
}
|
|
12861
12901
|
// The hint first, the clone second: that order is what stacks them in the
|
|
12862
12902
|
// top layer. A copy taken back in hand is already up there, and the hint
|
|
@@ -13027,6 +13067,7 @@ const startDragToCarryCopy = (
|
|
|
13027
13067
|
canLand,
|
|
13028
13068
|
tossDistance,
|
|
13029
13069
|
tossSpeed,
|
|
13070
|
+
tossBy,
|
|
13030
13071
|
});
|
|
13031
13072
|
|
|
13032
13073
|
// Let go of and still on the screen: from here until it is taken away
|
|
@@ -13075,12 +13116,17 @@ const startDragToCarryCopy = (
|
|
|
13075
13116
|
await settleCloneBack(cloneWrapper, draggedElement);
|
|
13076
13117
|
}
|
|
13077
13118
|
} else if (dropMeans === "land") {
|
|
13119
|
+
// Read before the copy is put down: landing bakes its position and
|
|
13120
|
+
// drops the transform, and where it came down is where the hand let
|
|
13121
|
+
// go of it.
|
|
13122
|
+
const landedAt = getRectInside(cloneWrapper, currentReleaseElement);
|
|
13078
13123
|
await landCopyOn(currentReleaseElement, (syncCloneWithDropTarget) =>
|
|
13079
|
-
onLand(
|
|
13080
|
-
getItemId(draggedElement),
|
|
13081
|
-
getItemId(currentReleaseElement),
|
|
13124
|
+
onLand({
|
|
13125
|
+
fromId: getItemId(draggedElement),
|
|
13126
|
+
toId: getItemId(currentReleaseElement),
|
|
13127
|
+
...landedAt,
|
|
13082
13128
|
syncCloneWithDropTarget,
|
|
13083
|
-
),
|
|
13129
|
+
}),
|
|
13084
13130
|
);
|
|
13085
13131
|
} else if (dropMeans === "reorder") {
|
|
13086
13132
|
await landCopyOn(currentReleaseElement, (syncCloneWithDropTarget) =>
|
|
@@ -13135,6 +13181,28 @@ const setCloneViewportRect = (cloneWrapper, el) => {
|
|
|
13135
13181
|
cloneWrapper.style.setProperty("--clone-height", `${rect.height}px`);
|
|
13136
13182
|
};
|
|
13137
13183
|
|
|
13184
|
+
// Where one box sits inside another, in that other's own content: its border and
|
|
13185
|
+
// its scroll are taken out, so the numbers say where IN the thing rather than
|
|
13186
|
+
// where in what is visible of it at that moment.
|
|
13187
|
+
const getRectInside = (element, containerElement) => {
|
|
13188
|
+
const rect = element.getBoundingClientRect();
|
|
13189
|
+
const containerRect = containerElement.getBoundingClientRect();
|
|
13190
|
+
return {
|
|
13191
|
+
x:
|
|
13192
|
+
rect.left -
|
|
13193
|
+
containerRect.left -
|
|
13194
|
+
containerElement.clientLeft +
|
|
13195
|
+
containerElement.scrollLeft,
|
|
13196
|
+
y:
|
|
13197
|
+
rect.top -
|
|
13198
|
+
containerRect.top -
|
|
13199
|
+
containerElement.clientTop +
|
|
13200
|
+
containerElement.scrollTop,
|
|
13201
|
+
width: rect.width,
|
|
13202
|
+
height: rect.height,
|
|
13203
|
+
};
|
|
13204
|
+
};
|
|
13205
|
+
|
|
13138
13206
|
// Creates the two-layer clone structure used for drag-to-reorder.
|
|
13139
13207
|
//
|
|
13140
13208
|
// Layer 1 — wrapper (navi-drag-clone-wrapper):
|
|
@@ -13383,6 +13451,17 @@ const createDragClone = (element, pointerEvent) => {
|
|
|
13383
13451
|
// (The original wears it too, but it is hidden — see navi-drag-clone-source.)
|
|
13384
13452
|
elementClone.setAttribute("data-grabbed", "");
|
|
13385
13453
|
elementClone.style.viewTransitionName = "navi-drag-clone";
|
|
13454
|
+
// The copy takes the wrapper's box, and nothing the page said about where the
|
|
13455
|
+
// ORIGINAL stands may place it: a piece drawn at "left: 40px; top: 130px" on
|
|
13456
|
+
// its board, a marker centred by a translate, a card pushed by a margin — the
|
|
13457
|
+
// deep copy carries all of that, inline styles included, and would sit that far
|
|
13458
|
+
// from the wrapper's corner, so from the hand. Written inline on the copy
|
|
13459
|
+
// because that is the one place that outranks both the inline values it copied
|
|
13460
|
+
// and any rule of the page's, without a stylesheet having to shout !important.
|
|
13461
|
+
elementClone.style.position = "absolute";
|
|
13462
|
+
elementClone.style.inset = "0";
|
|
13463
|
+
elementClone.style.margin = "0";
|
|
13464
|
+
elementClone.style.translate = "none";
|
|
13386
13465
|
|
|
13387
13466
|
wrapper.appendChild(elementClone);
|
|
13388
13467
|
// Beside the thing it copies, so it stands where that thing stands: every
|
|
@@ -14672,6 +14751,12 @@ const isAncestorOpen = (ancestor) => {
|
|
|
14672
14751
|
* own closed-state CSS ([navi-hidden], :not([popover])) for the custom
|
|
14673
14752
|
* renderers — so nothing inside one answers true here, while everything a
|
|
14674
14753
|
* trigger keeps on screen does.
|
|
14754
|
+
*
|
|
14755
|
+
* Ask it about an ancestor that is closed AND settled — on mount, or when
|
|
14756
|
+
* setting up a long-lived observer. A surface animating its way out still has a
|
|
14757
|
+
* box for the length of the animation (transition-behavior: allow-discrete on
|
|
14758
|
+
* display/overlay), so asked at the instant one closes this says "on screen"
|
|
14759
|
+
* about something on its way off it.
|
|
14675
14760
|
*/
|
|
14676
14761
|
const isDisplayedDespiteClosedAncestor = (element) => {
|
|
14677
14762
|
if (typeof element.checkVisibility !== "function") {
|
|
@@ -15332,6 +15417,20 @@ window.addEventListener("resize", (event) => {
|
|
|
15332
15417
|
const getVisibleViewportRect = () => {
|
|
15333
15418
|
const visualViewport = window.visualViewport;
|
|
15334
15419
|
const documentElement = document.documentElement;
|
|
15420
|
+
// Read FIRST, before the visual viewport just below — and used again in the
|
|
15421
|
+
// branch further down, so it is a read this function needs either way.
|
|
15422
|
+
//
|
|
15423
|
+
// The visual viewport's own numbers are refreshed with the frame's geometry,
|
|
15424
|
+
// and reading the layout viewport is what brings that geometry up to date.
|
|
15425
|
+
// Read them the other way round and the answer is the state as it was before
|
|
15426
|
+
// the caller's own measuring — every caller here measures an element moments
|
|
15427
|
+
// later, with getBoundingClientRect/offsetHeight, which forces exactly that
|
|
15428
|
+
// update. The box would then be measured in one layout state and placed in
|
|
15429
|
+
// another; on a phone opening its keyboard the two are a screen apart, the
|
|
15430
|
+
// popup lands where the pre-keyboard viewport put it, and nothing after
|
|
15431
|
+
// corrects it. Costs no extra layout: it moves the one the caller triggers
|
|
15432
|
+
// anyway rather than adding a second.
|
|
15433
|
+
const layoutViewportHeight = window.innerHeight;
|
|
15335
15434
|
if (!visualViewport) {
|
|
15336
15435
|
return {
|
|
15337
15436
|
left: 0,
|
|
@@ -15358,8 +15457,8 @@ const getVisibleViewportRect = () => {
|
|
|
15358
15457
|
) {
|
|
15359
15458
|
offsetLeft = 0;
|
|
15360
15459
|
offsetTop = 0;
|
|
15361
|
-
if (
|
|
15362
|
-
height =
|
|
15460
|
+
if (layoutViewportHeight > height) {
|
|
15461
|
+
height = layoutViewportHeight;
|
|
15363
15462
|
}
|
|
15364
15463
|
}
|
|
15365
15464
|
return {
|
|
@@ -15971,7 +16070,23 @@ const visibleRectEffect = (
|
|
|
15971
16070
|
let currentOpenableAncestor = selfOrClosestOpenableAncestor(element);
|
|
15972
16071
|
while (currentOpenableAncestor) {
|
|
15973
16072
|
const openableAncestor = currentOpenableAncestor;
|
|
15974
|
-
|
|
16073
|
+
const openableAncestorIsOpen = isAncestorOpen(openableAncestor);
|
|
16074
|
+
// A closed openable that keeps `element` on screen is the *trigger* of
|
|
16075
|
+
// what is closed rather than the thing itself — a picker's root, an
|
|
16076
|
+
// expandable's header, a <summary> all carry aria-expanded/open for a
|
|
16077
|
+
// surface they are not part of, and `element` here belongs to the
|
|
16078
|
+
// façade they keep showing the whole time. Its closed state hides
|
|
16079
|
+
// nothing of this element, so it must not count as a state that does.
|
|
16080
|
+
//
|
|
16081
|
+
// Read once, here, and kept for the effect's lifetime: the layout only
|
|
16082
|
+
// answers this question honestly about an ancestor that is already
|
|
16083
|
+
// closed and settled. Asked at the instant a surface closes, it still
|
|
16084
|
+
// says "on screen" for as long as a close animation keeps a box for it,
|
|
16085
|
+
// which is the opposite answer — so a surface closing later goes on
|
|
16086
|
+
// counting, unasked.
|
|
16087
|
+
const elementIsInAncestorFacade =
|
|
16088
|
+
!openableAncestorIsOpen && isDisplayedDespiteClosedAncestor(element);
|
|
16089
|
+
if (!openableAncestorIsOpen && !elementIsInAncestorFacade) {
|
|
15975
16090
|
ancestorClosedCount++;
|
|
15976
16091
|
pauseResizeWatching();
|
|
15977
16092
|
}
|
|
@@ -15980,6 +16095,9 @@ const visibleRectEffect = (
|
|
|
15980
16095
|
// eslint-disable-next-line no-loop-func
|
|
15981
16096
|
({ isOpen, toggleEvent }) => {
|
|
15982
16097
|
if (!isOpen) {
|
|
16098
|
+
if (elementIsInAncestorFacade) {
|
|
16099
|
+
return;
|
|
16100
|
+
}
|
|
15983
16101
|
ancestorClosedCount++;
|
|
15984
16102
|
pauseResizeWatching();
|
|
15985
16103
|
// Invalidates check()'s own "did anything actually change"
|
|
@@ -16008,7 +16126,7 @@ const visibleRectEffect = (
|
|
|
16008
16126
|
);
|
|
16009
16127
|
return;
|
|
16010
16128
|
}
|
|
16011
|
-
if (ancestorClosedCount > 0) {
|
|
16129
|
+
if (!elementIsInAncestorFacade && ancestorClosedCount > 0) {
|
|
16012
16130
|
ancestorClosedCount--;
|
|
16013
16131
|
}
|
|
16014
16132
|
if (ancestorClosedCount === 0) {
|
|
@@ -17030,21 +17148,17 @@ const parseTransitionDurationMs = (element, cssVarName, fallbackMs) => {
|
|
|
17030
17148
|
* A second reposition landing mid-animation cancels the pending one and
|
|
17031
17149
|
* flushes its own registered callbacks immediately (same spirit as a real
|
|
17032
17150
|
* `transitioncancel`), so nothing is left waiting on a superseded `onEnd`.
|
|
17151
|
+
* Every second reposition, animated or not — see
|
|
17152
|
+
* cancelPendingPositionTransition, which applyNewPosition calls on the path
|
|
17153
|
+
* that does not come through here.
|
|
17033
17154
|
*
|
|
17034
|
-
* `commitStyles()` below
|
|
17035
|
-
*
|
|
17036
|
-
*
|
|
17037
|
-
*
|
|
17038
|
-
* "none"` timing, and drops the finished Animation instead of leaving it.
|
|
17155
|
+
* `commitStyles()` below is what the specified `translate` reads once the
|
|
17156
|
+
* active duration elapses, so it must only ever run while this animation is
|
|
17157
|
+
* still the current placement: it writes THIS animation's target, which a
|
|
17158
|
+
* placement landing after it has already superseded.
|
|
17039
17159
|
*/
|
|
17040
17160
|
const notifyPositionTransition = (element, animation) => {
|
|
17041
|
-
|
|
17042
|
-
if (pending) {
|
|
17043
|
-
pending.animation.cancel();
|
|
17044
|
-
for (const callback of pending.endCallbacks) {
|
|
17045
|
-
callback();
|
|
17046
|
-
}
|
|
17047
|
-
}
|
|
17161
|
+
cancelPendingPositionTransition(element);
|
|
17048
17162
|
const endCallbacks = [];
|
|
17049
17163
|
dispatchCustomEvent(element, "navi_position_transition", {
|
|
17050
17164
|
onEnd: (callback) => {
|
|
@@ -17074,6 +17188,31 @@ const notifyPositionTransition = (element, animation) => {
|
|
|
17074
17188
|
});
|
|
17075
17189
|
};
|
|
17076
17190
|
|
|
17191
|
+
/**
|
|
17192
|
+
* Ends the placement animation in flight on `element`, if any, and flushes what
|
|
17193
|
+
* was waiting on it — what a new placement owes the old one, whether or not it
|
|
17194
|
+
* animates itself.
|
|
17195
|
+
*
|
|
17196
|
+
* The non-animated case is the one worth naming: a placement that just writes
|
|
17197
|
+
* `translate` leaves an animation started a moment earlier running, and that
|
|
17198
|
+
* animation commits ITS target when it ends, on top of the value written since.
|
|
17199
|
+
* The box then lands where a viewport that no longer exists put it, and nothing
|
|
17200
|
+
* comes after to correct it — a phone opening its keyboard fires exactly this
|
|
17201
|
+
* sequence, an animated "resize" followed by focus/size deliveries that do not
|
|
17202
|
+
* animate.
|
|
17203
|
+
*/
|
|
17204
|
+
const cancelPendingPositionTransition = (element) => {
|
|
17205
|
+
const pending = pendingPositionTransitions.get(element);
|
|
17206
|
+
if (!pending) {
|
|
17207
|
+
return;
|
|
17208
|
+
}
|
|
17209
|
+
pendingPositionTransitions.delete(element);
|
|
17210
|
+
pending.animation.cancel();
|
|
17211
|
+
for (const callback of pending.endCallbacks) {
|
|
17212
|
+
callback();
|
|
17213
|
+
}
|
|
17214
|
+
};
|
|
17215
|
+
|
|
17077
17216
|
/**
|
|
17078
17217
|
* Applies a `pickPositionRelativeTo` result to `element`, as a `translate`.
|
|
17079
17218
|
*
|
|
@@ -17196,6 +17335,8 @@ const applyNewPosition = (
|
|
|
17196
17335
|
},
|
|
17197
17336
|
);
|
|
17198
17337
|
notifyPositionTransition(element, animation);
|
|
17338
|
+
} else {
|
|
17339
|
+
cancelPendingPositionTransition(element);
|
|
17199
17340
|
}
|
|
17200
17341
|
// The specified translate is set to its final target right away,
|
|
17201
17342
|
// regardless of `shouldTransition` — the animation above only plays the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/dom",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.47",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "DOM utilities for writing frontend code",
|
|
6
6
|
"repository": {
|
|
@@ -35,12 +35,16 @@
|
|
|
35
35
|
"build": "node ./scripts/build.mjs",
|
|
36
36
|
"prepublishOnly": "npm run build"
|
|
37
37
|
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"@preact/signals": "^2.11.2",
|
|
40
|
+
"preact": "^11.0.0-beta.2"
|
|
41
|
+
},
|
|
38
42
|
"dependencies": {},
|
|
39
43
|
"devDependencies": {
|
|
40
44
|
"@jsenv/core": "../../../",
|
|
41
45
|
"@jsenv/navi": "../navi",
|
|
42
46
|
"@jsenv/snapshot": "../../tooling/snapshot",
|
|
43
|
-
"@preact/signals": "2.11.
|
|
47
|
+
"@preact/signals": "2.11.2",
|
|
44
48
|
"preact": "11.0.0-beta.2"
|
|
45
49
|
},
|
|
46
50
|
"publishConfig": {
|