@jsenv/navi 0.29.191 → 0.29.193
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/dev/jsenv_navi.js +346 -64
- package/dist/dev/jsenv_navi.js.map +11 -11
- package/dist/dev/jsenv_navi_side_effects.js +31 -4
- package/dist/dev/jsenv_navi_side_effects.js.map +3 -3
- package/dist/jsenv_navi.js +321 -64
- package/dist/jsenv_navi.js.map +11 -11
- package/dist/jsenv_navi_side_effects.js +31 -4
- package/dist/jsenv_navi_side_effects.js.map +3 -3
- package/docs/AI_INSTRUCTIONS.md +9 -0
- package/docs/interactions.md +104 -8
- package/docs/popup_backdrop.md +93 -0
- package/package.json +7 -3
package/dist/dev/jsenv_navi.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { installImportMetaCssBuild, windowHeightSignal, windowWidthSignal, visualViewportHeightSignal, visualViewportWidthSignal, getAppHeight, getAppWidth, coarsePointerSignal, smallTouchScreenSignal } from "./jsenv_navi_side_effects.js";
|
|
6
6
|
export { disableVirtualKeyboardOverlay } from "./jsenv_navi_side_effects.js";
|
|
7
|
-
import { elementIsFocusable, createIterableWeakSet, dispatchInternalCustomEvent, dispatchCustomEvent, getVisuallyVisibleInfo, getFirstVisuallyVisibleAncestor, getElementSignature, createPubSub, findEvent, createValueEffect, findFocusDelegateTarget, findFocusable, scrollIntoViewThroughScrollables, allowWheelThrough, dispatchPublicCustomEvent, resolveCSSColor, ELEMENT_SIZE_CHANGE, findSelfOrAncestorFixedPosition, visibleRectEffect, pickPositionRelativeTo, getBorderSizes, getPaddingSizes, applyNewPosition, measureLongestVisualLineWidth, chainEvent, keepTouchRefusable, waitForPressHeld, suppressClickAfterGesture, startDragToTravel, markDragSource, startDragTo, createEventGroupLogger, getKeyboardEventDefaultAction, activeElementSignal, normalizeStyle, mergeOneStyle, getPositionedParent, normalizeStyles, createGroupTransitionController, getBorderRadius, preventIntermediateScrollbar, createOpacityTransition, watchWheelTravel, scrollRoomTowards, getScrollContainer, closestOpenableAncestor, isAncestorOpen, isDisplayedDespiteClosedAncestor, observeAncestorOpenState, getAncestorOpenType, findBefore, findAfter, resolveCSSSize, hasCSSSizeUnit, releaseWheelGesture, getScrollIntoViewScopedOffsets, wheelGestureIsTakenFrom, claimWheelGesture, scrollIntoViewScoped, initFocusGroup, isTouchDrivenEvent, stringifyStyle as stringifyStyle$1, resolveOklchLightness, contrastColor, parsePositionArea, snapToPixel, trapFocusInside, trapScrollInside, onAncestorReopen, isPressDisputedByDrag, canScroll, measureWidestChildRow, performTabNavigation, dragAfterIntent, stickyAsRelativeCoords, createDragToMoveGestureController, getDropTargetInfo, setStyles, useActiveElement } from "@jsenv/dom";
|
|
7
|
+
import { elementIsFocusable, createIterableWeakSet, dispatchInternalCustomEvent, dispatchCustomEvent, getVisuallyVisibleInfo, getFirstVisuallyVisibleAncestor, getElementSignature, createPubSub, findEvent, createValueEffect, findFocusDelegateTarget, findFocusable, scrollIntoViewThroughScrollables, allowWheelThrough, dispatchPublicCustomEvent, resolveCSSColor, ELEMENT_SIZE_CHANGE, findSelfOrAncestorFixedPosition, visibleRectEffect, pickPositionRelativeTo, getBorderSizes, getPaddingSizes, applyNewPosition, measureLongestVisualLineWidth, chainEvent, keepTouchRefusable, waitForPressHeld, suppressClickAfterGesture, startDragToTravel, markDragSource, startDragTo, createEventGroupLogger, getKeyboardEventDefaultAction, activeElementSignal, normalizeStyle, mergeOneStyle, getPositionedParent, normalizeStyles, createGroupTransitionController, getBorderRadius, preventIntermediateScrollbar, createOpacityTransition, watchWheelTravel, scrollRoomTowards, getScrollContainer, closestOpenableAncestor, isAncestorOpen, isDisplayedDespiteClosedAncestor, observeAncestorOpenState, getAncestorOpenType, findBefore, findAfter, resolveCSSSize, hasCSSSizeUnit, releaseWheelGesture, getScrollIntoViewScopedOffsets, wheelGestureIsTakenFrom, claimWheelGesture, scrollIntoViewScoped, initFocusGroup, isTouchDrivenEvent, stringifyStyle as stringifyStyle$1, resolveOklchLightness, contrastColor, parsePositionArea, snapToPixel, trapFocusInside, trapScrollInside, getVirtualKeyboardOverlayHeight, onAncestorReopen, isPressDisputedByDrag, canScroll, measureWidestChildRow, performTabNavigation, dragAfterIntent, stickyAsRelativeCoords, createDragToMoveGestureController, getDropTargetInfo, setStyles, useActiveElement } from "@jsenv/dom";
|
|
8
8
|
export { chainEvent, clickIsSuppressed, contrastColor, createDragGestureController, dragAfterIntent, findEvent, markDragSource, startDragTo } from "@jsenv/dom";
|
|
9
9
|
import { signal, computed, effect, untracked, batch, useComputed, useSignal } from "@preact/signals";
|
|
10
10
|
import { isValidElement, createContext, render, h, toChildArray, options, cloneElement, Fragment as Fragment$1 } from "preact";
|
|
@@ -6019,7 +6019,13 @@ const css$12 = /* css */ `
|
|
|
6019
6019
|
To ensure ti goes above we put a z-index: 1, I hope it won't bite use in the future */
|
|
6020
6020
|
z-index: 1;
|
|
6021
6021
|
/* Callout styles */
|
|
6022
|
-
display:
|
|
6022
|
+
/* No display declared here on purpose: the UA rule hiding a closed popover
|
|
6023
|
+
is the only thing that takes a hidden callout off screen, and any author
|
|
6024
|
+
display beats it (author origin wins over the UA stylesheet whatever the
|
|
6025
|
+
specificity). Overridden, hidePopover() leaves the box painted — out of
|
|
6026
|
+
the top layer, so laid out against the nearest positioned ancestor while
|
|
6027
|
+
its placement is written in document coordinates: drawn at the wrong
|
|
6028
|
+
place instead of not at all. */
|
|
6023
6029
|
height: auto; /* User agent reset */
|
|
6024
6030
|
margin: 0;
|
|
6025
6031
|
padding: 0; /* User agent reset */
|
|
@@ -10524,17 +10530,27 @@ const swipeTypeOf = (axis, pulled) => {
|
|
|
10524
10530
|
* two, refuse.
|
|
10525
10531
|
*
|
|
10526
10532
|
* interactions={{ land: (event) => {
|
|
10527
|
-
* const { fromId, toId, syncCloneWithDropTarget } = event.detail;
|
|
10533
|
+
* const { fromId, toId, x, y, syncCloneWithDropTarget } = event.detail;
|
|
10528
10534
|
* …
|
|
10529
10535
|
* }}}
|
|
10530
10536
|
*
|
|
10531
10537
|
* `toId` is an element and never null: a copy over nothing is a release that meant
|
|
10532
|
-
* nothing, and the interaction does not happen at all
|
|
10538
|
+
* nothing, and the interaction does not happen at all — unless the element says
|
|
10539
|
+
* `data-toss-by="release-outside"` (see below), which gives that release a
|
|
10540
|
+
* meaning of its own.
|
|
10541
|
+
*
|
|
10542
|
+
* WHERE ON IT, in `x`, `y`, `width`, `height`: the box the copy came down in,
|
|
10543
|
+
* measured inside the place — its border and its scroll taken out. A place that is
|
|
10544
|
+
* a SURFACE — a plan, a map, a floor — has no element under the copy to name and
|
|
10545
|
+
* nothing to swap with: where it came down IS the answer, and `toId` says which
|
|
10546
|
+
* surface rather than which piece.
|
|
10533
10547
|
*
|
|
10534
10548
|
* `syncCloneWithDropTarget` takes an element here, which `reorder` has no use for:
|
|
10535
10549
|
* a place of a board can be larger than what stands on it (a quarter of a court, a
|
|
10536
10550
|
* square holding a smaller piece), and the copy has to come down where the piece
|
|
10537
|
-
* will be rather than filling the place. Left alone, it lands on the place itself
|
|
10551
|
+
* will be rather than filling the place. Left alone, it lands on the place itself —
|
|
10552
|
+
* so a surface either passes what the thing becomes or does not call it at all,
|
|
10553
|
+
* which leaves the copy where the hand put it, over the thing appearing there.
|
|
10538
10554
|
*
|
|
10539
10555
|
* WHICH ELEMENTS ARE PLACES: those marked `data-droppable`, and only those.
|
|
10540
10556
|
* Declaring `land` says an element can be CARRIED, which on a board is a different
|
|
@@ -10543,9 +10559,30 @@ const swipeTypeOf = (axis, pulled) => {
|
|
|
10543
10559
|
* case (dropped on a piece, the two swap). A list has no such distinction — every
|
|
10544
10560
|
* row is both, which is why `reorder` needs no marker in the markup.
|
|
10545
10561
|
*
|
|
10546
|
-
*
|
|
10547
|
-
* and a piece are siblings
|
|
10548
|
-
*
|
|
10562
|
+
* WHERE THE PLACES ARE LOOKED FOR: inside the carried element's PARENT, so a place
|
|
10563
|
+
* and a piece are siblings — and `data-drop-container` on an ancestor says
|
|
10564
|
+
* otherwise. Two arrangements need it, and both are the same one: what is carried
|
|
10565
|
+
* does not stand among the places. A palette is a strip BESIDE the surface it
|
|
10566
|
+
* fills, a marker already placed is drawn INSIDE the surface it can be put back
|
|
10567
|
+
* on, and in each case the search must cover what holds both. It holds the places
|
|
10568
|
+
* rather than being one — a surface carrying it would never be found from inside
|
|
10569
|
+
* itself. It is also what lets the copy travel there: named, the area it may cross
|
|
10570
|
+
* is the page rather than the source's own scroll area.
|
|
10571
|
+
*
|
|
10572
|
+
* <div data-drop-container>
|
|
10573
|
+
* <aside>{shapes.map((shape) => <Shape interactions={{ land: add }} />)}</aside>
|
|
10574
|
+
* <Plan id="plan" data-droppable>…</Plan>
|
|
10575
|
+
* </div>
|
|
10576
|
+
*
|
|
10577
|
+
* HOW A TOSS IS MADE: `data-toss-by`, beside `toss`. A THROW (`"throw"`, the
|
|
10578
|
+
* default) is far AND fast — the flick that gets rid of something, a list's
|
|
10579
|
+
* gesture, and it is judged before any landing. A RELEASE OUTSIDE
|
|
10580
|
+
* (`"release-outside"`) has no place under it — dragging a marker off a plan and
|
|
10581
|
+
* letting go, deliberate and never a flick, a surface's gesture. Each is named on
|
|
10582
|
+
* its own because each is wrong where the other is right: on a plan a fast drag
|
|
10583
|
+
* that ends ON it has not asked for the thing to go, and on a list a row let go of
|
|
10584
|
+
* beside it is a row put back. Both at once is
|
|
10585
|
+
* `data-toss-by="throw release-outside"`.
|
|
10549
10586
|
*
|
|
10550
10587
|
* Nothing of the gesture is decided here. `startDragTo` owns all of it — the
|
|
10551
10588
|
* copy carried above the page while the original keeps its place in the layout, the
|
|
@@ -10635,6 +10672,8 @@ const REORDERABLE_ATTRIBUTE = "data-reorderable";
|
|
|
10635
10672
|
// The same for `land`, except the markup is what writes it: a place of a board is
|
|
10636
10673
|
// not the same thing as a piece of it (see the top of this file).
|
|
10637
10674
|
const DROPPABLE_ATTRIBUTE = "data-droppable";
|
|
10675
|
+
// What holds the places, when the carried element does not stand among them.
|
|
10676
|
+
const DROP_CONTAINER_ATTRIBUTE = "data-drop-container";
|
|
10638
10677
|
// Which axes the drag walks: "x", "y" or "xy". Its default is not the same for
|
|
10639
10678
|
// every outcome — a list runs one way, and something being put somewhere goes
|
|
10640
10679
|
// wherever it is put.
|
|
@@ -10644,6 +10683,11 @@ const SLOP_ATTRIBUTE = "data-drag-slop";
|
|
|
10644
10683
|
const THRESHOLD_ATTRIBUTE = "data-drag-threshold";
|
|
10645
10684
|
const TOSS_DISTANCE_ATTRIBUTE = "data-toss-distance";
|
|
10646
10685
|
const TOSS_SPEED_ATTRIBUTE = "data-toss-speed";
|
|
10686
|
+
// How a toss is made here: "throw" (far and fast), "release-outside" (let go of
|
|
10687
|
+
// away from every place), or both.
|
|
10688
|
+
const TOSS_BY_ATTRIBUTE = "data-toss-by";
|
|
10689
|
+
const TOSS_BY_DEFAULT = "throw";
|
|
10690
|
+
const TOSS_WAYS = ["throw", "release-outside"];
|
|
10647
10691
|
|
|
10648
10692
|
defineInteractionDetector({
|
|
10649
10693
|
name: "drag",
|
|
@@ -10691,6 +10735,33 @@ defineInteractionDetector({
|
|
|
10691
10735
|
// the hand takes it: a board has places all around, a thing put somewhere has
|
|
10692
10736
|
// two axes to be put along, and a throw goes where it was thrown.
|
|
10693
10737
|
(canReorder && !canLand && !canToss ? "y" : "xy");
|
|
10738
|
+
// Where the places are, and what a release away from all of them means —
|
|
10739
|
+
// both read at setup for the same reason as the axes: they are what the
|
|
10740
|
+
// gesture is about, and it is what holds the two sides of it that says them.
|
|
10741
|
+
const dropContainer = element.closest(`[${DROP_CONTAINER_ATTRIBUTE}]`);
|
|
10742
|
+
const tossByHolder = element.closest(`[${TOSS_BY_ATTRIBUTE}]`);
|
|
10743
|
+
const tossBy = (
|
|
10744
|
+
tossByHolder?.getAttribute(TOSS_BY_ATTRIBUTE) || TOSS_BY_DEFAULT
|
|
10745
|
+
)
|
|
10746
|
+
.trim()
|
|
10747
|
+
.split(/\s+/);
|
|
10748
|
+
{
|
|
10749
|
+
for (const way of tossBy) {
|
|
10750
|
+
if (!TOSS_WAYS.includes(way)) {
|
|
10751
|
+
console.warn(
|
|
10752
|
+
`interactions: "${way}" is not a way a toss is made. ${TOSS_BY_ATTRIBUTE} takes "${TOSS_WAYS.join('", "')}", or both.`,
|
|
10753
|
+
);
|
|
10754
|
+
}
|
|
10755
|
+
}
|
|
10756
|
+
if (
|
|
10757
|
+
tossBy.includes("release-outside") &&
|
|
10758
|
+
(!canToss || (!canReorder && !canLand))
|
|
10759
|
+
) {
|
|
10760
|
+
console.warn(
|
|
10761
|
+
`interactions: ${TOSS_BY_ATTRIBUTE}="release-outside" makes a release away from every place mean the thing is gotten rid of, so it needs both "${TOSS}" and places to be away from. Declare "${TOSS}" beside "${REORDER}" or "${LAND}".`,
|
|
10762
|
+
);
|
|
10763
|
+
}
|
|
10764
|
+
}
|
|
10694
10765
|
|
|
10695
10766
|
if (canReorder) {
|
|
10696
10767
|
element.setAttribute(REORDERABLE_ATTRIBUTE, "");
|
|
@@ -10717,23 +10788,29 @@ defineInteractionDetector({
|
|
|
10717
10788
|
: canReorder
|
|
10718
10789
|
? `[${REORDERABLE_ATTRIBUTE}]`
|
|
10719
10790
|
: undefined,
|
|
10791
|
+
containerElement: dropContainer || undefined,
|
|
10720
10792
|
getItemId: (itemElement) => itemElement.id,
|
|
10721
10793
|
direction: { x: axes.includes("x"), y: axes.includes("y") },
|
|
10722
10794
|
// Where it may go, said in the DOM. A thing that is put somewhere stays
|
|
10723
10795
|
// inside what one can SEE of its container ("scrollport", not "scroll":
|
|
10724
10796
|
// the scrollable area can be far larger than the box, and "inside the box"
|
|
10725
|
-
// is what a hand expects). `data-drag-free` lifts that
|
|
10726
|
-
//
|
|
10727
|
-
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
|
|
10731
|
-
|
|
10797
|
+
// is what a hand expects). `data-drag-free` lifts that, and so does a
|
|
10798
|
+
// named container of places: they are somewhere else by construction, and
|
|
10799
|
+
// a copy kept in its own scroll area could never reach them. Left alone
|
|
10800
|
+
// for a throw, which frees the area on its own — it has to be able to
|
|
10801
|
+
// leave.
|
|
10802
|
+
areaConstraint:
|
|
10803
|
+
dropContainer || element.closest(`[data-drag-free]`)
|
|
10804
|
+
? "none"
|
|
10805
|
+
: canMove
|
|
10806
|
+
? "scrollport"
|
|
10807
|
+
: undefined,
|
|
10732
10808
|
threshold: readConfig(THRESHOLD_ATTRIBUTE, undefined),
|
|
10733
10809
|
longPressDelay: readConfig(DELAY_ATTRIBUTE, undefined),
|
|
10734
10810
|
longPressSlop: readConfig(SLOP_ATTRIBUTE, undefined),
|
|
10735
10811
|
tossDistance: readConfig(TOSS_DISTANCE_ATTRIBUTE, undefined),
|
|
10736
10812
|
tossSpeed: readConfig(TOSS_SPEED_ATTRIBUTE, undefined),
|
|
10813
|
+
tossBy,
|
|
10737
10814
|
// The one moment the gesture has that is not a release. Said here rather
|
|
10738
10815
|
// than from the press that led to it, because the press is only one of the
|
|
10739
10816
|
// two ways in: a finger holds still, a mouse travels a few pixels, and it
|
|
@@ -10756,12 +10833,7 @@ defineInteractionDetector({
|
|
|
10756
10833
|
toId,
|
|
10757
10834
|
syncCloneWithDropTarget,
|
|
10758
10835
|
}),
|
|
10759
|
-
onLand: (
|
|
10760
|
-
trigger(LAND, pointerDownEvent, {
|
|
10761
|
-
fromId,
|
|
10762
|
-
toId,
|
|
10763
|
-
syncCloneWithDropTarget,
|
|
10764
|
-
}),
|
|
10836
|
+
onLand: (detail) => trigger(LAND, pointerDownEvent, detail),
|
|
10765
10837
|
onToss: ({ gestureInfo }) =>
|
|
10766
10838
|
trigger(TOSS, pointerDownEvent, {
|
|
10767
10839
|
id: element.id,
|
|
@@ -19881,6 +19953,7 @@ import.meta.css = /* css */[`[data-scrollable] > .navi_loading_outline_wrapper,
|
|
|
19881
19953
|
|
|
19882
19954
|
[data-scrollable] {
|
|
19883
19955
|
overflow: var(--x-scrollable-overflow, auto);
|
|
19956
|
+
scroll-padding: var(--navi-scroll-padding, var(--navi-s));
|
|
19884
19957
|
--box-header-z-index: var(--navi-z-index-sticky);
|
|
19885
19958
|
--box-footer-z-index: var(--navi-z-index-sticky);
|
|
19886
19959
|
isolation: isolate;
|
|
@@ -19925,8 +19998,9 @@ import.meta.css = /* css */[`[data-scrollable] > .navi_loading_outline_wrapper,
|
|
|
19925
19998
|
border-bottom-left-radius: inherit;
|
|
19926
19999
|
outline-width: var(--navi-focus-outline-width);
|
|
19927
20000
|
outline-offset: calc(-1 * var(--navi-focus-outline-width));
|
|
19928
|
-
flex: 0 auto;
|
|
19929
20001
|
min-height: 0;
|
|
20002
|
+
scroll-padding: var(--navi-scroll-padding, var(--navi-s));
|
|
20003
|
+
flex: 0 auto;
|
|
19930
20004
|
overflow: auto;
|
|
19931
20005
|
|
|
19932
20006
|
&:focus-visible {
|
|
@@ -44890,6 +44964,7 @@ const mayHaveHiddenFocus = (event) => {
|
|
|
44890
44964
|
);
|
|
44891
44965
|
};
|
|
44892
44966
|
|
|
44967
|
+
const scrollportHeightMap = new WeakMap();
|
|
44893
44968
|
/**
|
|
44894
44969
|
* Scrolls whatever holds focus inside `popupEl` back into view, if the popup
|
|
44895
44970
|
* getting shorter has pushed it out.
|
|
@@ -44904,14 +44979,27 @@ const mayHaveHiddenFocus = (event) => {
|
|
|
44904
44979
|
* past its bottom edge — visually, swallowed by the footer. The browser does
|
|
44905
44980
|
* not redo a scroll-into-view it already answered, so this does.
|
|
44906
44981
|
*
|
|
44982
|
+
* Only what the shrink itself hid, though: with the keyboard up the user reads
|
|
44983
|
+
* the rest of the popup by scrolling the field away — to reach the submit under
|
|
44984
|
+
* it, typically — and the room keeps changing while they do (a keyboard settling
|
|
44985
|
+
* in two steps, a suggestion strip, a browser bar). Answering each of those by
|
|
44986
|
+
* scrolling the field back takes the popup away from wherever they had just
|
|
44987
|
+
* scrolled it, over and over: what they were reading cannot be reached at all
|
|
44988
|
+
* without blurring the field first, and the popup reads as unscrollable. So the
|
|
44989
|
+
* field is brought back only when it was in view before the room shrank, which
|
|
44990
|
+
* one remembered number answers: a resize moves neither scrollTop nor the
|
|
44991
|
+
* element's offset inside the scrolled content, so measuring against the height
|
|
44992
|
+
* the scrollport HAD is measuring the state before the change.
|
|
44993
|
+
*
|
|
44907
44994
|
* Scoped to the field's own scroll container (never the page): a popup traps
|
|
44908
44995
|
* scrolling precisely so the document underneath cannot move, and a plain
|
|
44909
44996
|
* scrollIntoView walks past a container whose scrollbar isn't visible — see
|
|
44910
44997
|
* scrollIntoViewScoped's own doc.
|
|
44911
44998
|
*
|
|
44912
|
-
* "nearest": the smallest scroll that makes it visible, and none at all when
|
|
44913
|
-
*
|
|
44914
|
-
*
|
|
44999
|
+
* "nearest": the smallest scroll that makes it visible, and none at all when it
|
|
45000
|
+
* already is. Where it lands is the container's own business — a navi scroller
|
|
45001
|
+
* keeps a band free at its edges so a field never comes back glued to one (see
|
|
45002
|
+
* scroll-padding in box.jsx).
|
|
44915
45003
|
*/
|
|
44916
45004
|
const keepFocusedElementVisible = (popupEl) => {
|
|
44917
45005
|
const { activeElement } = document;
|
|
@@ -44921,7 +45009,49 @@ const keepFocusedElementVisible = (popupEl) => {
|
|
|
44921
45009
|
if (!popupEl.contains(activeElement)) {
|
|
44922
45010
|
return;
|
|
44923
45011
|
}
|
|
44924
|
-
|
|
45012
|
+
const scrollContainer = getScrollContainer(activeElement);
|
|
45013
|
+
if (!scrollContainer || !popupEl.contains(scrollContainer)) {
|
|
45014
|
+
// What scrolls the field is outside the popup, which means the page: a
|
|
45015
|
+
// popup holds it still on purpose (trapScrollInside), so there is nothing
|
|
45016
|
+
// here to scroll back.
|
|
45017
|
+
return;
|
|
45018
|
+
}
|
|
45019
|
+
const scrollportHeight = scrollContainer.clientHeight;
|
|
45020
|
+
const scrollportHeightBefore = scrollportHeightMap.get(scrollContainer);
|
|
45021
|
+
scrollportHeightMap.set(scrollContainer, scrollportHeight);
|
|
45022
|
+
if (scrollportHeightBefore !== undefined) {
|
|
45023
|
+
if (scrollportHeight >= scrollportHeightBefore) {
|
|
45024
|
+
// Nothing was taken away, so nothing was hidden by this.
|
|
45025
|
+
return;
|
|
45026
|
+
}
|
|
45027
|
+
if (
|
|
45028
|
+
!isVisibleInScrollport(
|
|
45029
|
+
activeElement,
|
|
45030
|
+
scrollContainer,
|
|
45031
|
+
scrollportHeightBefore,
|
|
45032
|
+
)
|
|
45033
|
+
) {
|
|
45034
|
+
return;
|
|
45035
|
+
}
|
|
45036
|
+
}
|
|
45037
|
+
scrollIntoViewScoped(activeElement, {
|
|
45038
|
+
container: scrollContainer,
|
|
45039
|
+
block: "nearest",
|
|
45040
|
+
});
|
|
45041
|
+
};
|
|
45042
|
+
|
|
45043
|
+
// Whether any part of `el` was showing in `container` back when its scrollport
|
|
45044
|
+
// was `scrollportHeight` tall. Both boxes are read now: the container may have
|
|
45045
|
+
// moved as well as shrunk (a centered dialog re-centers itself), and the
|
|
45046
|
+
// difference between the two tops is what that move leaves alone.
|
|
45047
|
+
const isVisibleInScrollport = (el, container, scrollportHeight) => {
|
|
45048
|
+
const elRect = el.getBoundingClientRect();
|
|
45049
|
+
const containerRect = container.getBoundingClientRect();
|
|
45050
|
+
const elTop = elRect.top - containerRect.top + container.scrollTop;
|
|
45051
|
+
const elBottom = elTop + elRect.height;
|
|
45052
|
+
const scrollportTop = container.scrollTop;
|
|
45053
|
+
const scrollportBottom = scrollportTop + scrollportHeight;
|
|
45054
|
+
return elBottom > scrollportTop && elTop < scrollportBottom;
|
|
44925
45055
|
};
|
|
44926
45056
|
|
|
44927
45057
|
/**
|
|
@@ -44968,6 +45098,32 @@ const whenTransitionSettles = (el, onSettled) => {
|
|
|
44968
45098
|
};
|
|
44969
45099
|
};
|
|
44970
45100
|
|
|
45101
|
+
/**
|
|
45102
|
+
* Drops the document's text selection when it lives inside `el`, leaving a
|
|
45103
|
+
* selection made elsewhere on the page alone.
|
|
45104
|
+
*
|
|
45105
|
+
* A popup being closed takes its content with it, and a selection is a claim
|
|
45106
|
+
* on content the user can still act on: kept, it would outlive the surface it
|
|
45107
|
+
* was made on — painted on the box for the length of its exit transition, with
|
|
45108
|
+
* the handles and the copy toolbar a phone draws from the live selection
|
|
45109
|
+
* hanging over something that is going away — and reappear with the box on
|
|
45110
|
+
* the next opening. Dropping the selection is the only way to remove that
|
|
45111
|
+
* chrome: a `user-select: none` on the closing box hides the highlight in some
|
|
45112
|
+
* browsers only, and the handles are the browser's own, drawn from the
|
|
45113
|
+
* selection object rather than from any style.
|
|
45114
|
+
*/
|
|
45115
|
+
const clearTextSelectionInside = (el) => {
|
|
45116
|
+
const selection = window.getSelection();
|
|
45117
|
+
if (!selection || selection.rangeCount === 0) {
|
|
45118
|
+
return;
|
|
45119
|
+
}
|
|
45120
|
+
const range = selection.getRangeAt(0);
|
|
45121
|
+
if (!el.contains(range.commonAncestorContainer)) {
|
|
45122
|
+
return;
|
|
45123
|
+
}
|
|
45124
|
+
selection.removeAllRanges();
|
|
45125
|
+
};
|
|
45126
|
+
|
|
44971
45127
|
/**
|
|
44972
45128
|
* Disables pointer-events on `el` until its current CSS transition settles —
|
|
44973
45129
|
* avoids the cursor changing/something becoming clickable while the popup is
|
|
@@ -56696,6 +56852,15 @@ const css$E = /* css */`
|
|
|
56696
56852
|
scroll (a short body, an axis with nowhere to go) must not travel to
|
|
56697
56853
|
whatever is behind. */
|
|
56698
56854
|
overscroll-behavior: none;
|
|
56855
|
+
/* What the backdrop paints, resolved on the dialog rather than on the
|
|
56856
|
+
pseudo-element that paints it: ::backdrop takes no inline style and
|
|
56857
|
+
carries no attribute of its own, so the backdropColor/backdropFilter
|
|
56858
|
+
props land here — inline, beating every rule below — and the
|
|
56859
|
+
pseudo-element inherits whichever won. A colour and a filter travel
|
|
56860
|
+
together everywhere a backdrop is painted: see navi_css_vars.js for
|
|
56861
|
+
why a blur is not tied to what an outside click does. */
|
|
56862
|
+
--backdrop-background: var(--navi-backdrop-close-background);
|
|
56863
|
+
--backdrop-filter: var(--navi-backdrop-close-backdrop-filter);
|
|
56699
56864
|
|
|
56700
56865
|
/* Docking answers a different question than --dialog-max-width: a sheet
|
|
56701
56866
|
spans its container's full width, flush against the two side edges —
|
|
@@ -56746,6 +56911,7 @@ const css$E = /* css */`
|
|
|
56746
56911
|
&[data-flush-bottom][data-flush-left] {
|
|
56747
56912
|
border-bottom-left-radius: 0;
|
|
56748
56913
|
}
|
|
56914
|
+
|
|
56749
56915
|
/* The placement is a translate, so the translate property is spoken for
|
|
56750
56916
|
here (see applyNewPosition in visible_rect.js, which owns it and animates
|
|
56751
56917
|
it itself through the Web Animations API rather than through this file's
|
|
@@ -56753,26 +56919,26 @@ const css$E = /* css */`
|
|
|
56753
56919
|
to filter). An entrance animation moves the dialog through scale and
|
|
56754
56920
|
transform instead, which compose under it: see popup_css.js. */
|
|
56755
56921
|
|
|
56756
|
-
|
|
56757
|
-
background: var(--navi-backdrop-
|
|
56922
|
+
&[data-pointer-interaction-outside="capture"] {
|
|
56923
|
+
--backdrop-background: var(--navi-backdrop-capture-background);
|
|
56924
|
+
--backdrop-filter: var(--navi-backdrop-capture-backdrop-filter);
|
|
56758
56925
|
}
|
|
56759
|
-
|
|
56760
|
-
|
|
56761
|
-
|
|
56926
|
+
/* backdropVariant, after the rules it overrides: same specificity, so
|
|
56927
|
+
order is what decides. showModal() still makes the page inert either
|
|
56928
|
+
way — only the paint goes away. */
|
|
56929
|
+
&[data-backdrop-variant="discrete"] {
|
|
56930
|
+
--backdrop-background: var(--navi-backdrop-discrete-background);
|
|
56931
|
+
--backdrop-filter: var(--navi-backdrop-discrete-backdrop-filter);
|
|
56762
56932
|
}
|
|
56763
|
-
|
|
56764
|
-
|
|
56765
|
-
|
|
56766
|
-
|
|
56767
|
-
|
|
56768
|
-
page inert either way — only the paint goes away. */
|
|
56769
|
-
&[data-backdrop-variant="discrete"]::backdrop {
|
|
56770
|
-
background: var(--navi-backdrop-discrete-background);
|
|
56771
|
-
backdrop-filter: none;
|
|
56933
|
+
/* The one backdrop with nothing to blur through: "invisible" paints
|
|
56934
|
+
nothing at all, and a filter would still be seen. */
|
|
56935
|
+
&[data-backdrop-variant="invisible"] {
|
|
56936
|
+
--backdrop-background: transparent;
|
|
56937
|
+
--backdrop-filter: none;
|
|
56772
56938
|
}
|
|
56773
|
-
|
|
56774
|
-
background:
|
|
56775
|
-
backdrop-filter:
|
|
56939
|
+
&::backdrop {
|
|
56940
|
+
background: var(--backdrop-background);
|
|
56941
|
+
backdrop-filter: var(--backdrop-filter);
|
|
56776
56942
|
}
|
|
56777
56943
|
|
|
56778
56944
|
/* Nested under &[navi-animation] (not the other way around) so every
|
|
@@ -56882,6 +57048,17 @@ const css$E = /* css */`
|
|
|
56882
57048
|
in openEffect) gets pointer-events: none mid-transition. */
|
|
56883
57049
|
pointer-events: auto;
|
|
56884
57050
|
|
|
57051
|
+
/* Painted through the same two variables as the via-attribute renderer's
|
|
57052
|
+
::backdrop (see them for what each rule is for) — here they resolve on
|
|
57053
|
+
the element that paints, which is also the element the
|
|
57054
|
+
backdropColor/backdropFilter props are set on. Declared unconditionally
|
|
57055
|
+
first so a variable inherited from a dialog this popup was opened from
|
|
57056
|
+
can never reach the paint. */
|
|
57057
|
+
--backdrop-background: transparent;
|
|
57058
|
+
--backdrop-filter: none;
|
|
57059
|
+
background: var(--backdrop-background);
|
|
57060
|
+
backdrop-filter: var(--backdrop-filter);
|
|
57061
|
+
|
|
56885
57062
|
/* A plain div, unlike dialogEl itself (a real <dialog>, natively hidden
|
|
56886
57063
|
by default until .show()/.showModal() adds [open]) — needs its own
|
|
56887
57064
|
starting-hidden mechanism. [navi-hidden] is set from useDialogProps'
|
|
@@ -56898,23 +57075,20 @@ const css$E = /* css */`
|
|
|
56898
57075
|
/* Makes pointerInteractionOutsideEffect have a visible impact on backdrop */
|
|
56899
57076
|
&[data-pointer-interaction-outside="close"],
|
|
56900
57077
|
&[data-pointer-interaction-outside="cancel"] {
|
|
56901
|
-
background: var(--navi-backdrop-close-background);
|
|
57078
|
+
--backdrop-background: var(--navi-backdrop-close-background);
|
|
57079
|
+
--backdrop-filter: var(--navi-backdrop-close-backdrop-filter);
|
|
56902
57080
|
}
|
|
56903
57081
|
&[data-pointer-interaction-outside="capture"] {
|
|
56904
|
-
background: var(--navi-backdrop-capture-background);
|
|
56905
|
-
backdrop-filter: var(--navi-backdrop-capture-backdrop-filter);
|
|
57082
|
+
--backdrop-background: var(--navi-backdrop-capture-background);
|
|
57083
|
+
--backdrop-filter: var(--navi-backdrop-capture-backdrop-filter);
|
|
56906
57084
|
}
|
|
56907
|
-
|
|
56908
|
-
/* Same override as the via-attribute renderer's own ::backdrop rules
|
|
56909
|
-
above, on the real element this renderer uses instead — see them for
|
|
56910
|
-
the specificity/ordering reasoning. */
|
|
56911
57085
|
&[data-backdrop-variant="discrete"] {
|
|
56912
|
-
background: var(--navi-backdrop-discrete-background);
|
|
56913
|
-
backdrop-filter:
|
|
57086
|
+
--backdrop-background: var(--navi-backdrop-discrete-background);
|
|
57087
|
+
--backdrop-filter: var(--navi-backdrop-discrete-backdrop-filter);
|
|
56914
57088
|
}
|
|
56915
57089
|
&[data-backdrop-variant="invisible"] {
|
|
56916
|
-
background: transparent;
|
|
56917
|
-
backdrop-filter: none;
|
|
57090
|
+
--backdrop-background: transparent;
|
|
57091
|
+
--backdrop-filter: none;
|
|
56918
57092
|
}
|
|
56919
57093
|
|
|
56920
57094
|
/* overlay is a no-op here (this backdrop is a plain div, never a
|
|
@@ -57041,6 +57215,17 @@ const css$E = /* css */`
|
|
|
57041
57215
|
* barely-there dim. `"invisible"`: fully transparent. The dialog stays modal
|
|
57042
57216
|
* either way — this only changes how much it insists visually, never what
|
|
57043
57217
|
* an outside click does or whether the page behind stays reachable.
|
|
57218
|
+
* @param {string} [props.backdropColor] - The wash painted over what is
|
|
57219
|
+
* behind, for this popup alone: any CSS color (`"rgb(6 10 20 / 88%)"`).
|
|
57220
|
+
* Wins over `backdropVariant` and over the theme tokens
|
|
57221
|
+
* (`--navi-backdrop-*-background`), which is where the same choice goes
|
|
57222
|
+
* when it is the whole app's.
|
|
57223
|
+
* @param {string} [props.backdropFilter] - What that same wash does to the
|
|
57224
|
+
* picture underneath: `"blur(4px)"` to keep the page behind recognisable
|
|
57225
|
+
* while it stops being readable. A `backdrop-filter` value, so
|
|
57226
|
+
* `saturate()`/`grayscale()` work too. How far what is behind withdraws is
|
|
57227
|
+
* a question of paint, not of what an outside click does — a backdrop that
|
|
57228
|
+
* closes can blur.
|
|
57044
57229
|
* @param {boolean} [props.scrollCapture] - Traps scroll gestures inside the
|
|
57045
57230
|
* dialog so the page/container behind it can't scroll while it's open.
|
|
57046
57231
|
* A `layer="local"` dialog always locks its own positioned ancestor's
|
|
@@ -57377,6 +57562,13 @@ const useDialogProps = props => {
|
|
|
57377
57562
|
// always modal, so "none" here never makes the page behind reachable:
|
|
57378
57563
|
// it only stops the dim from being drawn.
|
|
57379
57564
|
backdropVariant = "auto",
|
|
57565
|
+
// The paint itself, when the tokens behind backdropVariant are not what
|
|
57566
|
+
// this one dialog wants. Named/forwarded rather than left in ...rest:
|
|
57567
|
+
// rest lands on the dialog element, and these belong to the backdrop —
|
|
57568
|
+
// which is the pseudo-element of one renderer and a sibling of the other,
|
|
57569
|
+
// so both objects below get them (see this file's CSS).
|
|
57570
|
+
backdropColor,
|
|
57571
|
+
backdropFilter,
|
|
57380
57572
|
scrollCapture: scrollCaptureProp,
|
|
57381
57573
|
// "auto" (default) → the dialog follows its content. "frozen" → measured
|
|
57382
57574
|
// once, held at that size while open. See this prop's own JSDoc above.
|
|
@@ -57811,6 +58003,33 @@ const useDialogProps = props => {
|
|
|
57811
58003
|
// recheck its own position whenever this dialog itself moves is
|
|
57812
58004
|
// handled generically by applyNewPosition itself (dispatches
|
|
57813
58005
|
// navi_position_change on every call) — nothing to do here.
|
|
58006
|
+
logPlacement(triggerEvent, position);
|
|
58007
|
+
};
|
|
58008
|
+
// The whole picture in one line: where the dialog ended up, and what it
|
|
58009
|
+
// believed about the room when it decided. Both are needed together — a box
|
|
58010
|
+
// that looks wrong on screen while these numbers are right means something
|
|
58011
|
+
// covers the screen that no API describes (a phone's autofill/suggestion
|
|
58012
|
+
// strip), and the absence of a line after the keyboard arrives means the
|
|
58013
|
+
// placement was never asked to run again.
|
|
58014
|
+
const logPlacement = (triggerEvent, position) => {
|
|
58015
|
+
// The decided target, never the current rect: the placement animates, so
|
|
58016
|
+
// a box read right after applying one is somewhere between the two and
|
|
58017
|
+
// reads like a decision nobody took.
|
|
58018
|
+
const {
|
|
58019
|
+
visualViewport
|
|
58020
|
+
} = window;
|
|
58021
|
+
// Reads nothing that brings the layout up to date — no getComputedStyle,
|
|
58022
|
+
// no window.innerWidth/innerHeight. That is the very thing this line is
|
|
58023
|
+
// here to observe (see getVisibleViewportRect in @jsenv/dom): a log that
|
|
58024
|
+
// forced it would hand the NEXT placement a fresh viewport and hide the
|
|
58025
|
+
// bug it was printed to show. Everything below is either already computed
|
|
58026
|
+
// (the pick's own numbers, "room" being the room it had) or free to read.
|
|
58027
|
+
const message = `placed on "${triggerEvent ? triggerEvent.type : "open"}": ${Math.round(position.width)}x${Math.round(position.height)} at ${Math.round(position.top)}->${Math.round(position.top + position.height)} | room ${Math.round(position.containerHeightAvailable)} | viewport ${Math.round(visualViewport.width)}x${Math.round(visualViewport.height)} +${Math.round(visualViewport.offsetLeft)},${Math.round(visualViewport.offsetTop)} | keyboard ${getVirtualKeyboardOverlayHeight()}`;
|
|
58028
|
+
if (triggerEvent) {
|
|
58029
|
+
debugPopup(triggerEvent, message);
|
|
58030
|
+
} else {
|
|
58031
|
+
debugPopup(message);
|
|
58032
|
+
}
|
|
57814
58033
|
};
|
|
57815
58034
|
// Cleared here rather than on close, where the box is deliberately left
|
|
57816
58035
|
// frozen at the size it was closing at (see the closing function's own
|
|
@@ -57958,6 +58177,7 @@ const useDialogProps = props => {
|
|
|
57958
58177
|
}
|
|
57959
58178
|
return closeEvent => {
|
|
57960
58179
|
debugPopup(`"${closeEvent.type}" on ${getElementSignature(closeEvent.target)} -> closeDialog`);
|
|
58180
|
+
clearTextSelectionInside(dialogEl);
|
|
57961
58181
|
dialogEl.setAttribute("aria-expanded", "false");
|
|
57962
58182
|
if (!isModal) {
|
|
57963
58183
|
openLocalDialogCount = Math.max(0, openLocalDialogCount - 1);
|
|
@@ -58045,7 +58265,9 @@ const useDialogProps = props => {
|
|
|
58045
58265
|
"styleCSSVars": DIALOG_STYLE_CSS_VARS,
|
|
58046
58266
|
"animationDuration": rest.animationDuration,
|
|
58047
58267
|
"data-pointer-interaction-outside": pointerInteractionOutsideEffect,
|
|
58048
|
-
"data-backdrop-variant": backdropVariant
|
|
58268
|
+
"data-backdrop-variant": backdropVariant,
|
|
58269
|
+
backdropColor,
|
|
58270
|
+
backdropFilter
|
|
58049
58271
|
});
|
|
58050
58272
|
Object.assign(contentProps, {
|
|
58051
58273
|
tabIndex,
|
|
@@ -58079,6 +58301,11 @@ const useDialogProps = props => {
|
|
|
58079
58301
|
// as the prop just above (and harmless for the custom renderer, whose
|
|
58080
58302
|
// real backdrop element gets it via backdropProps).
|
|
58081
58303
|
"data-backdrop-variant": backdropVariant,
|
|
58304
|
+
// Read by the native ::backdrop, which inherits them from here (see this
|
|
58305
|
+
// file's CSS) — the custom renderer's own backdrop element gets them via
|
|
58306
|
+
// backdropProps above.
|
|
58307
|
+
backdropColor,
|
|
58308
|
+
backdropFilter,
|
|
58082
58309
|
"styleCSSVars": DIALOG_STYLE_CSS_VARS,
|
|
58083
58310
|
...rest,
|
|
58084
58311
|
...autoFocusProps,
|
|
@@ -58195,6 +58422,8 @@ const DIALOG_PSEUDO_CLASSES = [":hover", ":active", ":focus", ":focus-visible",
|
|
|
58195
58422
|
// an inline border-radius would outrank them.
|
|
58196
58423
|
const DIALOG_STYLE_CSS_VARS = {
|
|
58197
58424
|
animationDuration: "--popup-animation-duration",
|
|
58425
|
+
backdropColor: "--backdrop-background",
|
|
58426
|
+
backdropFilter: "--backdrop-filter",
|
|
58198
58427
|
borderRadius: "--dialog-border-radius",
|
|
58199
58428
|
minWidth: "--dialog-min-width",
|
|
58200
58429
|
maxWidth: "--dialog-max-width",
|
|
@@ -58428,8 +58657,18 @@ const css$D = /* css */`
|
|
|
58428
58657
|
z-index: calc(var(--navi-z-index-popup) + var(--popover-stack-order, 0));
|
|
58429
58658
|
margin: 0;
|
|
58430
58659
|
padding: 0;
|
|
58431
|
-
|
|
58660
|
+
/* What this backdrop paints, in two variables the rules below write as
|
|
58661
|
+
defaults — so the backdropColor/backdropFilter props, inline on this
|
|
58662
|
+
very element, beat all of them. Declared unconditionally first so a
|
|
58663
|
+
variable inherited from a dialog this popover was opened from can never
|
|
58664
|
+
reach the paint. A colour and a filter travel together everywhere a
|
|
58665
|
+
backdrop is painted: see navi_css_vars.js for why a blur is not tied to
|
|
58666
|
+
what an outside click does. */
|
|
58667
|
+
--backdrop-background: transparent;
|
|
58668
|
+
--backdrop-filter: none;
|
|
58669
|
+
background: var(--backdrop-background);
|
|
58432
58670
|
border: none;
|
|
58671
|
+
backdrop-filter: var(--backdrop-filter);
|
|
58433
58672
|
/* Always clickable while actually rendered (display: none/hidePopover()
|
|
58434
58673
|
while genuinely closed already makes it non-interactive on its own)
|
|
58435
58674
|
— an outside click should close the popover even while it's still
|
|
@@ -58460,11 +58699,12 @@ const css$D = /* css */`
|
|
|
58460
58699
|
/* Makes pointerInteractionOutsideEffect have a visible impact on backdrop */
|
|
58461
58700
|
&[data-pointer-interaction-outside="close"],
|
|
58462
58701
|
&[data-pointer-interaction-outside="cancel"] {
|
|
58463
|
-
background: var(--navi-backdrop-close-background);
|
|
58702
|
+
--backdrop-background: var(--navi-backdrop-close-background);
|
|
58703
|
+
--backdrop-filter: var(--navi-backdrop-close-backdrop-filter);
|
|
58464
58704
|
}
|
|
58465
58705
|
&[data-pointer-interaction-outside="capture"] {
|
|
58466
|
-
background: var(--navi-backdrop-capture-background);
|
|
58467
|
-
backdrop-filter: var(--navi-backdrop-capture-backdrop-filter);
|
|
58706
|
+
--backdrop-background: var(--navi-backdrop-capture-background);
|
|
58707
|
+
--backdrop-filter: var(--navi-backdrop-capture-backdrop-filter);
|
|
58468
58708
|
}
|
|
58469
58709
|
|
|
58470
58710
|
/* backdropVariant overrides whatever the effect above picked — same
|
|
@@ -58473,12 +58713,14 @@ const css$D = /* css */`
|
|
|
58473
58713
|
and still pointer-events: auto, so an outside click keeps doing
|
|
58474
58714
|
exactly what pointerInteractionOutsideEffect says. */
|
|
58475
58715
|
&[data-backdrop-variant="discrete"] {
|
|
58476
|
-
background: var(--navi-backdrop-discrete-background);
|
|
58477
|
-
backdrop-filter:
|
|
58716
|
+
--backdrop-background: var(--navi-backdrop-discrete-background);
|
|
58717
|
+
--backdrop-filter: var(--navi-backdrop-discrete-backdrop-filter);
|
|
58478
58718
|
}
|
|
58719
|
+
/* The one backdrop with nothing to blur through: "invisible" paints
|
|
58720
|
+
nothing at all, and a filter would still be seen. */
|
|
58479
58721
|
&[data-backdrop-variant="invisible"] {
|
|
58480
|
-
background: transparent;
|
|
58481
|
-
backdrop-filter: none;
|
|
58722
|
+
--backdrop-background: transparent;
|
|
58723
|
+
--backdrop-filter: none;
|
|
58482
58724
|
}
|
|
58483
58725
|
|
|
58484
58726
|
/* navi-animation mirrors the content popover's own resolved value (set
|
|
@@ -58558,6 +58800,17 @@ const css$D = /* css */`
|
|
|
58558
58800
|
* changes how much the popover insists on being the thing you deal with.
|
|
58559
58801
|
* Ignored when `pointerInteractionOutsideEffect="none"` (there is no
|
|
58560
58802
|
* backdrop at all then, and outside clicks pass through).
|
|
58803
|
+
* @param {string} [props.backdropColor] - The wash painted over what is
|
|
58804
|
+
* behind, for this popup alone: any CSS color (`"rgb(6 10 20 / 88%)"`).
|
|
58805
|
+
* Wins over `backdropVariant` and over the theme tokens
|
|
58806
|
+
* (`--navi-backdrop-*-background`), which is where the same choice goes
|
|
58807
|
+
* when it is the whole app's.
|
|
58808
|
+
* @param {string} [props.backdropFilter] - What that same wash does to the
|
|
58809
|
+
* picture underneath: `"blur(4px)"` to keep the page behind recognisable
|
|
58810
|
+
* while it stops being readable. A `backdrop-filter` value, so
|
|
58811
|
+
* `saturate()`/`grayscale()` work too. How far what is behind withdraws is
|
|
58812
|
+
* a question of paint, not of what an outside click does — a backdrop that
|
|
58813
|
+
* closes can blur.
|
|
58561
58814
|
* @param {boolean} [props.scrollCapture] - Traps scroll gestures inside the
|
|
58562
58815
|
* popover so the page/container behind it can't scroll while it's open.
|
|
58563
58816
|
* @param {boolean} [props.focusCapture] - Traps Tab navigation inside the
|
|
@@ -58869,6 +59122,12 @@ const usePopoverProps = props => {
|
|
|
58869
59122
|
// the paint the effect implies; "discrete"/"none" tone it down or
|
|
58870
59123
|
// remove it entirely without giving up the outside click.
|
|
58871
59124
|
backdropVariant = "auto",
|
|
59125
|
+
// The paint itself, when the tokens behind backdropVariant are not what
|
|
59126
|
+
// this one popover wants. Named/forwarded rather than left in ...rest:
|
|
59127
|
+
// rest lands on the popover element, and these belong to its backdrop,
|
|
59128
|
+
// which is a sibling element (see this file's top comment).
|
|
59129
|
+
backdropColor,
|
|
59130
|
+
backdropFilter,
|
|
58872
59131
|
scrollCapture,
|
|
58873
59132
|
focusCapture,
|
|
58874
59133
|
// "auto" (default) → the popover follows its content. "frozen" → measured
|
|
@@ -59466,6 +59725,7 @@ const usePopoverProps = props => {
|
|
|
59466
59725
|
// reason: only ever built here.
|
|
59467
59726
|
return closeEvent => {
|
|
59468
59727
|
debugPopup(closeEvent, `closePopover()`);
|
|
59728
|
+
clearTextSelectionInside(popoverEl);
|
|
59469
59729
|
popoverEl.setAttribute("aria-expanded", "false");
|
|
59470
59730
|
// Set regardless of isTopLayer — see the open side's own identical
|
|
59471
59731
|
// comment (openEffect above) for why hidePopover() alone isn't
|
|
@@ -59581,6 +59841,8 @@ const usePopoverProps = props => {
|
|
|
59581
59841
|
"animationDuration": rest.animationDuration,
|
|
59582
59842
|
"data-pointer-interaction-outside": pointerInteractionOutsideEffect,
|
|
59583
59843
|
"data-backdrop-variant": backdropVariant,
|
|
59844
|
+
backdropColor,
|
|
59845
|
+
backdropFilter,
|
|
59584
59846
|
"onMouseDown": mouseDownEvent => {
|
|
59585
59847
|
if (mouseDownEvent.button !== 0) {
|
|
59586
59848
|
return;
|
|
@@ -59685,6 +59947,8 @@ const POPOVER_PSEUDO_CLASSES = [":hover", ":active", ":focus", ":focus-visible",
|
|
|
59685
59947
|
// handling).
|
|
59686
59948
|
const POPUP_STYLE_CSS_VARS = {
|
|
59687
59949
|
animationDuration: "--popup-animation-duration",
|
|
59950
|
+
backdropColor: "--backdrop-background",
|
|
59951
|
+
backdropFilter: "--backdrop-filter",
|
|
59688
59952
|
minWidth: "--popover-min-width",
|
|
59689
59953
|
maxWidth: "--popover-max-width",
|
|
59690
59954
|
minHeight: "--popover-min-height",
|
|
@@ -59803,6 +60067,10 @@ const css$C = /* css */`@layer navi {
|
|
|
59803
60067
|
* how visible the backdrop is, independently of what an outside click
|
|
59804
60068
|
* does. Unlike `pointerInteractionOutsideEffect` above, this one needs no
|
|
59805
60069
|
* default here — `"auto"` already means the same thing on both sides.
|
|
60070
|
+
* @param {string} [props.backdropColor] - Forwarded as-is (both understand it
|
|
60071
|
+
* identically): the wash the backdrop paints over what is behind.
|
|
60072
|
+
* @param {string} [props.backdropFilter] - Forwarded as-is: what that wash
|
|
60073
|
+
* does to the picture underneath, `"blur(4px)"` and the like.
|
|
59806
60074
|
* @param {boolean|"auto"|"fading"|"scaling"|"sliding"|"expanding"|`slide-from-${string}`|`expand-${string}`} [props.animation]
|
|
59807
60075
|
* - Forwarded as-is.
|
|
59808
60076
|
* @param {string} [props.animationDuration] - Forwarded as-is.
|
|
@@ -60671,6 +60939,8 @@ const PickerContentInsidePopup = props => {
|
|
|
60671
60939
|
// Named/forwarded rather than left in ...rest: rest goes to the picker
|
|
60672
60940
|
// element itself, not the popup, and this belongs to the popup.
|
|
60673
60941
|
backdropVariant,
|
|
60942
|
+
backdropColor,
|
|
60943
|
+
backdropFilter,
|
|
60674
60944
|
dialogExpand,
|
|
60675
60945
|
dialogExpandX,
|
|
60676
60946
|
dialogExpandY,
|
|
@@ -60746,6 +61016,8 @@ const PickerContentInsidePopup = props => {
|
|
|
60746
61016
|
scrollCapture: scrollCapture,
|
|
60747
61017
|
pointerInteractionOutsideEffect: pointerLock ? "capture" : pointerInteractionOutsideEffect,
|
|
60748
61018
|
backdropVariant: backdropVariant,
|
|
61019
|
+
backdropColor: backdropColor,
|
|
61020
|
+
backdropFilter: backdropFilter,
|
|
60749
61021
|
focusCapture: isPopover ? focusCapture : undefined,
|
|
60750
61022
|
expand: isPopover ? undefined : dialogExpand,
|
|
60751
61023
|
expandX: isPopover ? undefined : dialogExpandX,
|
|
@@ -69665,6 +69937,8 @@ const PickerFirstResolver = props => {
|
|
|
69665
69937
|
* escapeEffect?: "cancel" | "close",
|
|
69666
69938
|
* pointerInteractionOutsideEffect?: "close" | "cancel" | "capture",
|
|
69667
69939
|
* backdropVariant?: "auto" | "discrete" | "invisible",
|
|
69940
|
+
* backdropColor?: string,
|
|
69941
|
+
* backdropFilter?: string,
|
|
69668
69942
|
* ref?: import("ignore:preact").RefObject<HTMLElement>,
|
|
69669
69943
|
* [key: string]: any,
|
|
69670
69944
|
* }>}
|
|
@@ -69913,6 +70187,11 @@ const PickerFirstResolver = props => {
|
|
|
69913
70187
|
* is the paint `pointerInteractionOutsideEffect` implies, `"discrete"` a
|
|
69914
70188
|
* barely-there dim, `"invisible"` fully transparent. For a picker that closes on
|
|
69915
70189
|
* an outside click without wanting to dim the page for it.
|
|
70190
|
+
* @param {string} [backdropColor] The wash the popup paints over what is
|
|
70191
|
+
* behind, for this picker alone. See Dialog's own doc.
|
|
70192
|
+
* @param {string} [backdropFilter] What that wash does to the picture
|
|
70193
|
+
* underneath (`"blur(4px)"`), independently of what a click outside does.
|
|
70194
|
+
* See Dialog's own doc.
|
|
69916
70195
|
* @param {number|string} [marginWithContainer] Minimum gap kept between the
|
|
69917
70196
|
* popup and the edges of what contains it (the viewport, or the picker's own
|
|
69918
70197
|
* positioned ancestor for `popupLayer="local"`). Caps the popup's size as
|
|
@@ -72324,6 +72603,8 @@ const css$n = /* css */`.navi_split_button {
|
|
|
72324
72603
|
* dockedOnSmallTouchScreen?: boolean,
|
|
72325
72604
|
* marginWithContainer?: number | string,
|
|
72326
72605
|
* backdropVariant?: "auto" | "discrete" | "invisible",
|
|
72606
|
+
* backdropColor?: string,
|
|
72607
|
+
* backdropFilter?: string,
|
|
72327
72608
|
* pointerInteractionOutsideEffect?: "close" | "cancel" | "capture",
|
|
72328
72609
|
* escapeEffect?: "cancel" | "close",
|
|
72329
72610
|
* popupLayer?: "top" | "local",
|
|
@@ -72370,6 +72651,7 @@ const css$n = /* css */`.navi_split_button {
|
|
|
72370
72651
|
* `dialogMaxWidth`/`Height`,
|
|
72371
72652
|
* `marginWithContainer`, `popoverMode`, `popoverSpacing`, `popupLayer`,
|
|
72372
72653
|
* `popupTestId`, `popupWidthFitContent`, `popoverMaxHeight`, `backdropVariant`,
|
|
72654
|
+
* `backdropColor`, `backdropFilter`,
|
|
72373
72655
|
* `pointerInteractionOutsideEffect`, `escapeEffect`, `closeOnFocusOut`,
|
|
72374
72656
|
* `scrollCapture`, `focusCapture`, `popupBackgroundColor`,
|
|
72375
72657
|
* `popupBorderRadius`, `animation`. See picker.jsx for what each one says.
|
|
@@ -72570,7 +72852,7 @@ const SplitButton = props => {
|
|
|
72570
72852
|
// What the Picker's popup answers to — Picker's own popup props, named here so
|
|
72571
72853
|
// a caller reaches all of them through the split button (see picker.jsx's JSDoc
|
|
72572
72854
|
// for what each one says).
|
|
72573
|
-
const POPUP_PROP_SET = new Set(["mode", "popupLayer", "popupTestId", "positionArea", "popoverMode", "popoverSpacing", "popupWidthFitContent", "popoverMaxHeight", "dialogMinWidth", "dialogMinHeight", "dialogMaxWidth", "dialogMaxHeight", "dialogExpand", "dialogExpandX", "dialogExpandY", "dockedOnSmallTouchScreen", "marginWithContainer", "backdropVariant", "pointerInteractionOutsideEffect", "escapeEffect", "closeOnFocusOut", "scrollCapture", "focusCapture", "popupBackgroundColor", "popupBorderRadius", "animation"]);
|
|
72855
|
+
const POPUP_PROP_SET = new Set(["mode", "popupLayer", "popupTestId", "positionArea", "popoverMode", "popoverSpacing", "popupWidthFitContent", "popoverMaxHeight", "dialogMinWidth", "dialogMinHeight", "dialogMaxWidth", "dialogMaxHeight", "dialogExpand", "dialogExpandX", "dialogExpandY", "dockedOnSmallTouchScreen", "marginWithContainer", "backdropVariant", "backdropColor", "backdropFilter", "pointerInteractionOutsideEffect", "escapeEffect", "closeOnFocusOut", "scrollCapture", "focusCapture", "popupBackgroundColor", "popupBorderRadius", "animation"]);
|
|
72574
72856
|
const splitPopupProps = props => {
|
|
72575
72857
|
const popupProps = {};
|
|
72576
72858
|
const boxProps = {};
|