@jsenv/navi 0.29.324 → 0.29.325
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/README.md +1 -1
- package/dist/dev/jsenv_navi.js +174 -116
- package/dist/dev/jsenv_navi.js.map +8 -8
- package/dist/jsenv_navi.js +141 -116
- package/dist/jsenv_navi.js.map +8 -8
- package/docs/AI_INSTRUCTIONS.md +3 -2
- package/docs/dialog_shape.md +38 -18
- package/docs/drag_to_travel.md +3 -3
- package/docs/popup_backdrop.md +9 -7
- package/docs/popup_open.md +51 -16
- package/package.json +2 -2
package/dist/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, isPressDrivenClick, waitForTap, waitForPressHeld, suppressClickAfterGesture, startDragToTravel, dragSourceThatStoodDown, markDragSource, refuseDragTo, startDragTo, installPanZoom, getKeyboardEventDefaultAction, activeElementSignal, normalizeStyle, mergeOneStyle, getPositionedParent, normalizeStyles, createGroupTransitionController, getBorderRadius, preventIntermediateScrollbar, createOpacityTransition, watchWheelTravel, scrollRoomTowards, getScrollContainer, isTouchDrivenEvent, scrollIntoViewScoped, closestOpenableAncestor, isAncestorOpen, isDisplayedDespiteClosedAncestor, observeAncestorOpenState, getAncestorOpenType, findBefore, findAfter, resolveCSSSize, hasCSSSizeUnit, releaseWheelGesture, getScrollIntoViewScopedOffsets, wheelGestureIsTakenFrom, claimWheelGesture, initFocusGroup, 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, isPressDrivenClick, waitForTap, waitForPressHeld, suppressClickAfterGesture, startDragToTravel, dragSourceThatStoodDown, markDragSource, refuseDragTo, startDragTo, installPanZoom, createInternalCustomEvent, getKeyboardEventDefaultAction, activeElementSignal, normalizeStyle, mergeOneStyle, getPositionedParent, normalizeStyles, createGroupTransitionController, getBorderRadius, preventIntermediateScrollbar, createOpacityTransition, watchWheelTravel, scrollRoomTowards, getScrollContainer, isTouchDrivenEvent, scrollIntoViewScoped, closestOpenableAncestor, isAncestorOpen, isDisplayedDespiteClosedAncestor, observeAncestorOpenState, getAncestorOpenType, findBefore, findAfter, resolveCSSSize, hasCSSSizeUnit, releaseWheelGesture, getScrollIntoViewScopedOffsets, wheelGestureIsTakenFrom, claimWheelGesture, initFocusGroup, stringifyStyle as stringifyStyle$1, resolveOklchLightness, contrastColor, parsePositionArea, snapToPixel, trapFocusInside, trapScrollInside, 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, createElement, Fragment as Fragment$1 } from "preact";
|
|
@@ -12616,6 +12616,12 @@ const useExecuteAction = (
|
|
|
12616
12616
|
// whose command sent — is stored as the callout display target, so the
|
|
12617
12617
|
// message appears on whoever asked rather than on the whole control.
|
|
12618
12618
|
const element = elementRef.current;
|
|
12619
|
+
if (!element) {
|
|
12620
|
+
// The control left the page while its run was out (its own answer can
|
|
12621
|
+
// unmount it, see the outcome events below): there is no box to hang
|
|
12622
|
+
// the refusal on. onActionError is still told, by the run's side effect.
|
|
12623
|
+
return;
|
|
12624
|
+
}
|
|
12619
12625
|
let target = requester;
|
|
12620
12626
|
// A requester that is no longer on the page is not a place to show
|
|
12621
12627
|
// anything: the clear cross leaves with the value it optimistically
|
|
@@ -12718,12 +12724,20 @@ const useExecuteAction = (
|
|
|
12718
12724
|
// Either three callbacks, one per outcome, or a single one for "however
|
|
12719
12725
|
// this ends" — it receives `{ aborted, reason }`, `{ error }` or
|
|
12720
12726
|
// `{ data }`, so a caller that only needs to know the action settled
|
|
12721
|
-
// (and whether it worked) does not have to register three.
|
|
12727
|
+
// (and whether it worked) does not have to register three. Each also
|
|
12728
|
+
// receives the outcome event (navi_action_abort/error/end) as its
|
|
12729
|
+
// second argument.
|
|
12722
12730
|
const addSideEffect = (sideEffect) => {
|
|
12723
12731
|
if (typeof sideEffect === "function") {
|
|
12724
|
-
addAbortCallback((reason) =>
|
|
12725
|
-
|
|
12726
|
-
|
|
12732
|
+
addAbortCallback((reason, outcomeEvent) =>
|
|
12733
|
+
sideEffect({ aborted: true, reason }, outcomeEvent),
|
|
12734
|
+
);
|
|
12735
|
+
addErrorCallback((error, outcomeEvent) =>
|
|
12736
|
+
sideEffect({ error }, outcomeEvent),
|
|
12737
|
+
);
|
|
12738
|
+
addCompleteCallback((data, outcomeEvent) =>
|
|
12739
|
+
sideEffect({ data }, outcomeEvent),
|
|
12740
|
+
);
|
|
12727
12741
|
return;
|
|
12728
12742
|
}
|
|
12729
12743
|
const { abort, error, complete } = sideEffect;
|
|
@@ -12731,56 +12745,6 @@ const useExecuteAction = (
|
|
|
12731
12745
|
addErrorCallback(error);
|
|
12732
12746
|
addCompleteCallback(complete);
|
|
12733
12747
|
};
|
|
12734
|
-
addSideEffect({
|
|
12735
|
-
abort: (reason) => {
|
|
12736
|
-
const element = elementRef.current;
|
|
12737
|
-
if (
|
|
12738
|
-
// at this stage the action side effect might have removed the <element> from the DOM
|
|
12739
|
-
// (in theory no because action side effect are batched to happen after)
|
|
12740
|
-
// but other side effects might do this
|
|
12741
|
-
element
|
|
12742
|
-
) {
|
|
12743
|
-
dispatchInternalCustomEvent(element, "navi_action_abort", {
|
|
12744
|
-
...sharedActionEventDetail,
|
|
12745
|
-
reason,
|
|
12746
|
-
});
|
|
12747
|
-
}
|
|
12748
|
-
},
|
|
12749
|
-
error: (error) => {
|
|
12750
|
-
if (errorEffect === "show_validation_message") {
|
|
12751
|
-
addErrorMessage(error, { requester });
|
|
12752
|
-
} else if (errorEffect === "throw") {
|
|
12753
|
-
setError(error);
|
|
12754
|
-
}
|
|
12755
|
-
|
|
12756
|
-
const element = elementRef.current;
|
|
12757
|
-
if (
|
|
12758
|
-
// at this stage the action side effect might have removed the <element> from the DOM
|
|
12759
|
-
// (in theory no because action side effect are batched to happen after)
|
|
12760
|
-
// but other side effects might do this
|
|
12761
|
-
element
|
|
12762
|
-
) {
|
|
12763
|
-
dispatchInternalCustomEvent(element, "navi_action_error", {
|
|
12764
|
-
...sharedActionEventDetail,
|
|
12765
|
-
error,
|
|
12766
|
-
});
|
|
12767
|
-
}
|
|
12768
|
-
},
|
|
12769
|
-
complete: (data) => {
|
|
12770
|
-
const element = elementRef.current;
|
|
12771
|
-
if (
|
|
12772
|
-
// at this stage the action side effect might have removed the <element> from the DOM
|
|
12773
|
-
// (in theory no because action side effect are batched to happen after)
|
|
12774
|
-
// but other side effects might do this
|
|
12775
|
-
element
|
|
12776
|
-
) {
|
|
12777
|
-
dispatchInternalCustomEvent(element, "navi_action_end", {
|
|
12778
|
-
...sharedActionEventDetail,
|
|
12779
|
-
data,
|
|
12780
|
-
});
|
|
12781
|
-
}
|
|
12782
|
-
},
|
|
12783
|
-
});
|
|
12784
12748
|
|
|
12785
12749
|
const actionStartEventDetail = {
|
|
12786
12750
|
...sharedActionEventDetail,
|
|
@@ -12792,13 +12756,50 @@ const useExecuteAction = (
|
|
|
12792
12756
|
actionStartEventDetail,
|
|
12793
12757
|
);
|
|
12794
12758
|
|
|
12759
|
+
// The outcome is told twice: to the element, when there still is one,
|
|
12760
|
+
// and to the side effects registered at navi_action_start, always. A
|
|
12761
|
+
// run can outlive its control — the run's own answer, written to a
|
|
12762
|
+
// store the parent reads to decide what it draws, unmounts the control
|
|
12763
|
+
// one microtask before the run settles — and the element is then no
|
|
12764
|
+
// place to dispatch to: Preact drops a detached element's listeners.
|
|
12765
|
+
// The side effects are the run's, not the element's, so the event
|
|
12766
|
+
// reaches them either way.
|
|
12767
|
+
const tellOutcome = (outcomeEventName, outcomeEventDetail, trigger) => {
|
|
12768
|
+
const outcomeEvent = createInternalCustomEvent(outcomeEventName, {
|
|
12769
|
+
...sharedActionEventDetail,
|
|
12770
|
+
...outcomeEventDetail,
|
|
12771
|
+
});
|
|
12772
|
+
const element = elementRef.current;
|
|
12773
|
+
if (element) {
|
|
12774
|
+
element.dispatchEvent(outcomeEvent);
|
|
12775
|
+
}
|
|
12776
|
+
trigger(outcomeEvent);
|
|
12777
|
+
};
|
|
12778
|
+
|
|
12795
12779
|
const runAction = () => {
|
|
12796
12780
|
return action[method]({
|
|
12797
12781
|
event: actionEvent,
|
|
12798
12782
|
reason: `"${event.type}" event on ${getElementSignature(event.target)}`,
|
|
12799
|
-
onAbort:
|
|
12800
|
-
|
|
12801
|
-
|
|
12783
|
+
onAbort: (reason) => {
|
|
12784
|
+
tellOutcome("navi_action_abort", { reason }, (outcomeEvent) => {
|
|
12785
|
+
triggerAbort(reason, outcomeEvent);
|
|
12786
|
+
});
|
|
12787
|
+
},
|
|
12788
|
+
onError: (error) => {
|
|
12789
|
+
if (errorEffect === "show_validation_message") {
|
|
12790
|
+
addErrorMessage(error, { requester });
|
|
12791
|
+
} else if (errorEffect === "throw") {
|
|
12792
|
+
setError(error);
|
|
12793
|
+
}
|
|
12794
|
+
tellOutcome("navi_action_error", { error }, (outcomeEvent) => {
|
|
12795
|
+
triggerError(error, outcomeEvent);
|
|
12796
|
+
});
|
|
12797
|
+
},
|
|
12798
|
+
onComplete: (data) => {
|
|
12799
|
+
tellOutcome("navi_action_end", { data }, (outcomeEvent) => {
|
|
12800
|
+
triggerComplete(data, outcomeEvent);
|
|
12801
|
+
});
|
|
12802
|
+
},
|
|
12802
12803
|
});
|
|
12803
12804
|
};
|
|
12804
12805
|
|
|
@@ -39868,10 +39869,24 @@ const useInteractiveProps = (props, {
|
|
|
39868
39869
|
// aborted run, whose promise is awaited to completion (see
|
|
39869
39870
|
// performRun in actions.js) — which is exactly what "the server is
|
|
39870
39871
|
// done with it" means, and therefore when the queued request may go.
|
|
39871
|
-
e.detail.addSideEffect(outcome => {
|
|
39872
|
+
e.detail.addSideEffect((outcome, outcomeEvent) => {
|
|
39872
39873
|
uiStateController.actionInFlight = false;
|
|
39873
39874
|
uiStateController.runningActionSignal.value = null;
|
|
39874
39875
|
uiStateController.parallelGuard?.release(uiStateController);
|
|
39876
|
+
// The outcome callbacks are told from here, the run's side effect,
|
|
39877
|
+
// and not from the onnavi_action_* handlers below: the run can
|
|
39878
|
+
// outlive this control (its own answer, written to a store the
|
|
39879
|
+
// parent reads, unmounts it one microtask before it settles), and
|
|
39880
|
+
// whoever wears the run — a parent's `loading` following these,
|
|
39881
|
+
// see 12_picker_card_demo.html — must hear it end all the same.
|
|
39882
|
+
// The handlers below keep what needs the element.
|
|
39883
|
+
if (outcome.aborted) {
|
|
39884
|
+
onActionAborted?.(outcomeEvent);
|
|
39885
|
+
} else if ("error" in outcome) {
|
|
39886
|
+
onActionError?.(outcome.error, outcomeEvent);
|
|
39887
|
+
} else {
|
|
39888
|
+
onActionEnd?.(outcome.data, outcomeEvent);
|
|
39889
|
+
}
|
|
39875
39890
|
const queuedEvent = uiStateController.queuedActionAllowedEvent;
|
|
39876
39891
|
if (!queuedEvent) {
|
|
39877
39892
|
syncOptimisticAttribute(false);
|
|
@@ -39911,7 +39926,6 @@ const useInteractiveProps = (props, {
|
|
|
39911
39926
|
if (resetOnAbort && !superseded) {
|
|
39912
39927
|
dispatchRequestResetUIState(e.currentTarget, e);
|
|
39913
39928
|
}
|
|
39914
|
-
onActionAborted?.(e);
|
|
39915
39929
|
},
|
|
39916
39930
|
onnavi_action_error: e => {
|
|
39917
39931
|
const {
|
|
@@ -39920,7 +39934,6 @@ const useInteractiveProps = (props, {
|
|
|
39920
39934
|
if (resetOnError) {
|
|
39921
39935
|
dispatchRequestResetUIState(e.currentTarget, e);
|
|
39922
39936
|
}
|
|
39923
|
-
onActionError?.(error, e);
|
|
39924
39937
|
uiStateController.onActionError(e);
|
|
39925
39938
|
},
|
|
39926
39939
|
onnavi_action_end: e => {
|
|
@@ -39928,7 +39941,6 @@ const useInteractiveProps = (props, {
|
|
|
39928
39941
|
data
|
|
39929
39942
|
} = e.detail;
|
|
39930
39943
|
debugAction(e, `action end with data: ${JSON.stringify(data)}`);
|
|
39931
|
-
onActionEnd?.(data, e);
|
|
39932
39944
|
controlRootProps.onnavi_action_end?.(e);
|
|
39933
39945
|
uiStateController.onActionEnd(e);
|
|
39934
39946
|
|
|
@@ -59316,34 +59328,44 @@ const css$E = /* css */`
|
|
|
59316
59328
|
* `showModal()`'d (native focus trap, `Escape`-to-cancel, hardware
|
|
59317
59329
|
* back-button dismissal, rest-of-document made inert), without one it is
|
|
59318
59330
|
* shown through the Popover API and the page behind stays live.
|
|
59319
|
-
* @param {boolean} [props.dockedOnSmallTouchScreen] - Turns
|
|
59320
|
-
*
|
|
59321
|
-
* screen, and leaves it alone otherwise
|
|
59322
|
-
*
|
|
59323
|
-
* the
|
|
59324
|
-
*
|
|
59325
|
-
*
|
|
59326
|
-
*
|
|
59327
|
-
*
|
|
59328
|
-
*
|
|
59329
|
-
*
|
|
59330
|
-
*
|
|
59331
|
+
* @param {boolean|"top"|"bottom"} [props.dockedOnSmallTouchScreen] - Turns
|
|
59332
|
+
* the dialog into a sheet (docked flush to one edge, full width) on a small
|
|
59333
|
+
* touch screen, and leaves it alone otherwise: under a mouse the centered box
|
|
59334
|
+
* is already the right shape, while on a phone a centered box ends up cramped
|
|
59335
|
+
* between the keyboard and the top of the screen. The value says which edge
|
|
59336
|
+
* the sheet rests on. `true` (or `"top"`) rests it on the top edge, out of
|
|
59337
|
+
* the virtual keyboard's way: a field tapped in the sheet raises the keyboard
|
|
59338
|
+
* below it, and the question and the field stay where the finger found them.
|
|
59339
|
+
* `"bottom"` rests it on the bottom edge, where the thumbs are — for a sheet
|
|
59340
|
+
* that is read and tapped (a list, a couple of buttons, a confirmation) and
|
|
59341
|
+
* holds nothing that raises a keyboard; one that does is reflowed into the
|
|
59342
|
+
* strip left above the keyboard at every keystroke. The edge is said here
|
|
59343
|
+
* rather than through `positionArea`, which places both shapes:
|
|
59344
|
+
* `positionArea="bottom"` would also pin the centered box to the bottom of a
|
|
59345
|
+
* desktop window. Both halves of the name matter (`smallTouchScreenSignal`):
|
|
59346
|
+
* touch alone would dock a big touch screen — a tablet, a kiosk panel — a
|
|
59347
|
+
* whole screen away from where the finger just tapped, and size alone would
|
|
59348
|
+
* dock a narrow desktop window, which is still a mouse. It supplies defaults
|
|
59349
|
+
* for `positionArea`, `marginWithContainer`, `expandX` and `scrollCapture`,
|
|
59350
|
+
* so any of them can still be pinned explicitly — including `expandX={false}`,
|
|
59331
59351
|
* which opts the docked dialog out of the full-width stretch and leaves it a
|
|
59332
|
-
* floating box
|
|
59352
|
+
* floating box against its edge. It also withdraws `maxWidth` while docked: a
|
|
59333
59353
|
* sheet is container-wide by definition, and a `maxWidth` is an answer about
|
|
59334
59354
|
* the *centered* shape, so the two can be stated together (`maxWidth="16rem"
|
|
59335
59355
|
* dockedOnSmallTouchScreen`) and each applies where it means something.
|
|
59336
59356
|
* `minWidth` needs no such rule — its floor is below the full width — and
|
|
59337
59357
|
* `maxHeight`/`minHeight` keep applying, a sheet being content-tall.
|
|
59338
|
-
* Ignored entirely when `expandY`
|
|
59339
|
-
*
|
|
59340
|
-
*
|
|
59341
|
-
*
|
|
59342
|
-
*
|
|
59343
|
-
*
|
|
59344
|
-
*
|
|
59345
|
-
*
|
|
59346
|
-
*
|
|
59358
|
+
* Ignored entirely when `expandY` (or `expand`) is set: a dialog already
|
|
59359
|
+
* filling the height touches both edges, so docking could only take away the
|
|
59360
|
+
* shape the caller asked for. Re-resolves live as the pointer type or the
|
|
59361
|
+
* window size changes. A sheet is also pushed back through the edge it rests
|
|
59362
|
+
* on to close it (down for a bottom sheet, up for a top one), held by its
|
|
59363
|
+
* header (a `Box` with the `header` prop) and by anything else carrying
|
|
59364
|
+
* `data-swipe-grip`. The rest of the sheet is left to what it holds, so a
|
|
59365
|
+
* board something is dragged across keeps its own gestures. See
|
|
59366
|
+
* `swipe_to_close.js`. In dev, a `"bottom"` sheet found holding a field that
|
|
59367
|
+
* raises the keyboard is warned about at open, on any screen — the mistake
|
|
59368
|
+
* itself only shows on a phone.
|
|
59347
59369
|
* @param {string} [props.positionArea="center"] - Where to dock the dialog
|
|
59348
59370
|
* within its container (the viewport for `layer="top"`, the positioned
|
|
59349
59371
|
* ancestor for `layer="local"`) — Dialog is never anchored to a real
|
|
@@ -59709,28 +59731,28 @@ const DialogLocal = props => {
|
|
|
59709
59731
|
* own to render: a modal's is the native `::backdrop`, and `backdrop={false}`
|
|
59710
59732
|
* has none at all.
|
|
59711
59733
|
*/
|
|
59712
|
-
// What a dialog turns into on a small touch screen
|
|
59713
|
-
//
|
|
59714
|
-
//
|
|
59715
|
-
//
|
|
59734
|
+
// What a dialog turns into on a small touch screen: a sheet flush against one
|
|
59735
|
+
// edge of the screen. Which edge is the caller's word (the prop's value, see
|
|
59736
|
+
// its JSDoc), the top one unless told "bottom": the cheap mistake must be the
|
|
59737
|
+
// default one — a sheet docked top by mistake is a little farther from the
|
|
59738
|
+
// thumb, a sheet docked bottom by mistake fights the virtual keyboard, which
|
|
59739
|
+
// rises from that very edge, on every keystroke.
|
|
59716
59740
|
// Only defaults: an explicitly passed prop still wins, so the docked shape can
|
|
59717
59741
|
// be adjusted one axis at a time instead of being all-or-nothing.
|
|
59718
59742
|
const DOCKED = {
|
|
59719
|
-
positionArea: "bottom",
|
|
59720
59743
|
marginWithContainer: 0,
|
|
59721
59744
|
expandX: true,
|
|
59722
|
-
// A sheet
|
|
59723
|
-
//
|
|
59724
|
-
// reasoning as "bottom" above, applied to the gesture instead of the shape.
|
|
59745
|
+
// A sheet is dragged with a thumb, and a drag that runs past its own edge
|
|
59746
|
+
// must not land on the page behind it.
|
|
59725
59747
|
scrollCapture: true
|
|
59726
59748
|
};
|
|
59727
59749
|
|
|
59728
|
-
// Where a
|
|
59729
|
-
// with `header`, plus anything the application marked as one more.
|
|
59730
|
-
// else in the sheet is content the finger came to operate — a board
|
|
59731
|
-
// dragged across, a list, a map — and a press there belongs to it. A
|
|
59732
|
-
// no header and nothing marked is not pushed
|
|
59733
|
-
// own controls, by the backdrop and by Escape.
|
|
59750
|
+
// Where a sheet is held to push it back through its edge: the strip a Box
|
|
59751
|
+
// declares with `header`, plus anything the application marked as one more.
|
|
59752
|
+
// Everything else in the sheet is content the finger came to operate — a board
|
|
59753
|
+
// a piece is dragged across, a list, a map — and a press there belongs to it. A
|
|
59754
|
+
// sheet with no header and nothing marked is not pushed back at all; it is
|
|
59755
|
+
// closed by its own controls, by the backdrop and by Escape.
|
|
59734
59756
|
const DOCKED_SWIPE_GRIP = "[data-header],[data-swipe-grip]";
|
|
59735
59757
|
const useDialogProps = props => {
|
|
59736
59758
|
const backdropProps = {};
|
|
@@ -59836,12 +59858,12 @@ const useDialogProps = props => {
|
|
|
59836
59858
|
// Only a small touch screen changes anything: on a mouse — and on a touch
|
|
59837
59859
|
// screen too big to reach the bottom edge of — a dialog already wants to be
|
|
59838
59860
|
// the centered box it is by default, so there is nothing to resolve.
|
|
59839
|
-
// expandY cancels the docking outright:
|
|
59840
|
-
//
|
|
59841
|
-
//
|
|
59842
|
-
// caller asked for (and arm a swipe-down on something that never rose).
|
|
59861
|
+
// expandY cancels the docking outright: a dialog already filling the height
|
|
59862
|
+
// touches both edges — all docking could still do is take away the shape
|
|
59863
|
+
// the caller asked for (and arm a swipe on something that never rose).
|
|
59843
59864
|
const isDocked = dockedOnSmallTouchScreen && smallTouchScreenSignal.value && !expandY;
|
|
59844
|
-
const
|
|
59865
|
+
const dockedEdge = dockedOnSmallTouchScreen === "bottom" ? "bottom" : "top";
|
|
59866
|
+
const positionArea = positionAreaProp ?? (isDocked ? dockedEdge : "center");
|
|
59845
59867
|
const marginWithContainer = marginWithContainerProp ?? (isDocked ? DOCKED.marginWithContainer :
|
|
59846
59868
|
// A share of whatever holds the dialog: the app's own screen for a
|
|
59847
59869
|
// top-layer one — where appw is exactly "3% of the container", the
|
|
@@ -59903,12 +59925,12 @@ const useDialogProps = props => {
|
|
|
59903
59925
|
y: "center",
|
|
59904
59926
|
x: "center"
|
|
59905
59927
|
};
|
|
59906
|
-
// Pushing the sheet back
|
|
59907
|
-
//
|
|
59908
|
-
// actually resting on
|
|
59909
|
-
//
|
|
59910
|
-
const
|
|
59911
|
-
const onSwipePointerDown =
|
|
59928
|
+
// Pushing the sheet back through the edge it rests on closes it — the way
|
|
59929
|
+
// it came in, and the way the thumb on that edge already pushes. Only a sheet
|
|
59930
|
+
// actually resting on an edge: anywhere else the gesture would send the
|
|
59931
|
+
// dialog somewhere it never came from.
|
|
59932
|
+
const swipeToCloseSide = isDocked && (parsedPositionArea.y === "top" || parsedPositionArea.y === "bottom") ? parsedPositionArea.y : null;
|
|
59933
|
+
const onSwipePointerDown = swipeToCloseSide ? createSwipeToClose(swipeToCloseSide, {
|
|
59912
59934
|
grip: DOCKED_SWIPE_GRIP
|
|
59913
59935
|
}) : null;
|
|
59914
59936
|
// A corner sitting exactly on the container's own corner must not be
|
|
@@ -60540,12 +60562,12 @@ const useDialogProps = props => {
|
|
|
60540
60562
|
"data-flush-right": flushEdges.right ? "" : undefined,
|
|
60541
60563
|
"data-flush-bottom": flushEdges.bottom ? "" : undefined,
|
|
60542
60564
|
"data-flush-left": flushEdges.left ? "" : undefined,
|
|
60543
|
-
"data-swipe-to-close":
|
|
60565
|
+
"data-swipe-to-close": swipeToCloseSide ?? undefined,
|
|
60544
60566
|
// The axis the sheet travels on when it is pushed back, said to the shared
|
|
60545
60567
|
// gesture layer: it is what a box travelling inside the sheet reads to know
|
|
60546
60568
|
// this axis is already walked (see @jsenv/dom's drag_to_travel).
|
|
60547
|
-
"data-drag-travel":
|
|
60548
|
-
"data-travel-by-drag":
|
|
60569
|
+
"data-drag-travel": swipeToCloseSide ? SWIPE_AXIS_BY_SIDE[swipeToCloseSide] : undefined,
|
|
60570
|
+
"data-travel-by-drag": swipeToCloseSide ? SWIPE_AXIS_BY_SIDE[swipeToCloseSide] : undefined,
|
|
60549
60571
|
"onPointerDown": e => {
|
|
60550
60572
|
rest.onPointerDown?.(e);
|
|
60551
60573
|
onSwipePointerDown?.(e);
|
|
@@ -62339,8 +62361,8 @@ const css$C = /* css */`@layer navi {
|
|
|
62339
62361
|
* @param {string} [props.positionAreaFixed] - **Popover-only**, same guard.
|
|
62340
62362
|
* @param {string} [props.positionAreaWhenAnchorIsInvalid] - **Popover-only**,
|
|
62341
62363
|
* same guard.
|
|
62342
|
-
* @param {boolean} [props.dockedOnSmallTouchScreen] -
|
|
62343
|
-
* popover is never a
|
|
62364
|
+
* @param {boolean|"top"|"bottom"} [props.dockedOnSmallTouchScreen] -
|
|
62365
|
+
* **Dialog-only** (a popover is never a sheet), destructured out for the same reason
|
|
62344
62366
|
* turned around: it must not land on the popover element as a stray DOM
|
|
62345
62367
|
* attribute when the screen-size resolution picks `mode="popover"`. Where
|
|
62346
62368
|
* that resolution lands is what decides whether it applies at all, so a
|
|
@@ -62368,7 +62390,7 @@ const css$C = /* css */`@layer navi {
|
|
|
62368
62390
|
* honoured in either mode — a wall-less `Dialog` is shown through the
|
|
62369
62391
|
* Popover API rather than `showModal()` — so which mode the screen-size
|
|
62370
62392
|
* resolution picks says nothing about whether the page behind stays live.
|
|
62371
|
-
* It is also what makes a sheet docked to
|
|
62393
|
+
* It is also what makes a sheet docked to an edge of a phone's screen
|
|
62372
62394
|
* (`dockedOnSmallTouchScreen`) non-modal.
|
|
62373
62395
|
* @param {"auto"|"discrete"|"invisible"} [props.backdropVariant] - Forwarded
|
|
62374
62396
|
* as-is to whichever component renders (both understand it identically):
|
|
@@ -74973,7 +74995,7 @@ const css$n = /* css */`.navi_split_button {
|
|
|
74973
74995
|
* dialogExpand?: boolean,
|
|
74974
74996
|
* dialogExpandX?: boolean,
|
|
74975
74997
|
* dialogExpandY?: boolean,
|
|
74976
|
-
* dockedOnSmallTouchScreen?: boolean,
|
|
74998
|
+
* dockedOnSmallTouchScreen?: boolean | "top" | "bottom",
|
|
74977
74999
|
* marginWithContainer?: number | string,
|
|
74978
75000
|
* backdrop?: boolean,
|
|
74979
75001
|
* backdropVariant?: "auto" | "discrete" | "invisible",
|
|
@@ -84401,6 +84423,9 @@ const createSlot = (SlotRenderer = Box) => {
|
|
|
84401
84423
|
slotPropsSignal.value = props;
|
|
84402
84424
|
useLayoutEffect(() => {
|
|
84403
84425
|
return () => {
|
|
84426
|
+
// Within one diff preact mounts the newcomer before unmounting the
|
|
84427
|
+
// leaver, so the leaver may no longer be the filler by the time it
|
|
84428
|
+
// is cleaned up.
|
|
84404
84429
|
if (filler !== fillerRef) {
|
|
84405
84430
|
return;
|
|
84406
84431
|
}
|