@jsenv/navi 0.29.323 → 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 +2 -0
- package/dist/dev/jsenv_navi.js +312 -244
- package/dist/dev/jsenv_navi.js.map +22 -22
- package/dist/jsenv_navi.js +279 -244
- package/dist/jsenv_navi.js.map +22 -22
- package/docs/AI_INSTRUCTIONS.md +6 -3
- package/docs/dialog_shape.md +38 -18
- package/docs/drag_to_travel.md +3 -3
- package/docs/popup_backdrop.md +39 -6
- package/docs/popup_open.md +67 -0
- package/package.json +2 -2
package/dist/dev/jsenv_navi.js
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
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, createEventGroupLogger, 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, getVirtualKeyboardOverlayHeight, 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, createEventGroupLogger, 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, 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
|
-
import { isValidElement, createContext, render, h, toChildArray, options, cloneElement, Fragment as Fragment$1 } from "preact";
|
|
10
|
+
import { isValidElement, createContext, render, h, toChildArray, options, cloneElement, createElement, Fragment as Fragment$1 } from "preact";
|
|
11
11
|
import { useErrorBoundary, useLayoutEffect, useContext, useCallback, useRef, useState, useEffect, useMemo, useId } from "preact/hooks";
|
|
12
12
|
import { humanizeI18n, prefixFirstAndIndentRemainingLines, setRuntimeLangSource, formatDuration, formatMonth, formatDay, resolveTimeRangePrecision, formatDatePlaceholder, toDate, getRelativeDay, formatDayRelative, formatMonthPlaceholder, formatWeekPlaceholder, formatDatetimePlaceholder, formatDatetime, toTimeOfDay, formatTimeOfDay, formatTime, formatMinuteDuration, formatSecondDuration, formatHourDuration, formatTimeRelative, formatNumber, interpolateText, installInterpolateJsx } from "@jsenv/humanize";
|
|
13
13
|
export { createI18n, formatDatetime, formatDay, formatDayRelative, formatDuration, formatHourDuration, formatMinuteDuration, formatMonth, formatNumber, formatSecondDuration, formatTime, formatTimeOfDay, formatTimeRange, formatTimeRelative, interpolateText } from "@jsenv/humanize";
|
|
@@ -13207,6 +13207,12 @@ const useExecuteAction = (
|
|
|
13207
13207
|
// whose command sent — is stored as the callout display target, so the
|
|
13208
13208
|
// message appears on whoever asked rather than on the whole control.
|
|
13209
13209
|
const element = elementRef.current;
|
|
13210
|
+
if (!element) {
|
|
13211
|
+
// The control left the page while its run was out (its own answer can
|
|
13212
|
+
// unmount it, see the outcome events below): there is no box to hang
|
|
13213
|
+
// the refusal on. onActionError is still told, by the run's side effect.
|
|
13214
|
+
return;
|
|
13215
|
+
}
|
|
13210
13216
|
let target = requester;
|
|
13211
13217
|
// A requester that is no longer on the page is not a place to show
|
|
13212
13218
|
// anything: the clear cross leaves with the value it optimistically
|
|
@@ -13310,12 +13316,20 @@ const useExecuteAction = (
|
|
|
13310
13316
|
// Either three callbacks, one per outcome, or a single one for "however
|
|
13311
13317
|
// this ends" — it receives `{ aborted, reason }`, `{ error }` or
|
|
13312
13318
|
// `{ data }`, so a caller that only needs to know the action settled
|
|
13313
|
-
// (and whether it worked) does not have to register three.
|
|
13319
|
+
// (and whether it worked) does not have to register three. Each also
|
|
13320
|
+
// receives the outcome event (navi_action_abort/error/end) as its
|
|
13321
|
+
// second argument.
|
|
13314
13322
|
const addSideEffect = (sideEffect) => {
|
|
13315
13323
|
if (typeof sideEffect === "function") {
|
|
13316
|
-
addAbortCallback((reason) =>
|
|
13317
|
-
|
|
13318
|
-
|
|
13324
|
+
addAbortCallback((reason, outcomeEvent) =>
|
|
13325
|
+
sideEffect({ aborted: true, reason }, outcomeEvent),
|
|
13326
|
+
);
|
|
13327
|
+
addErrorCallback((error, outcomeEvent) =>
|
|
13328
|
+
sideEffect({ error }, outcomeEvent),
|
|
13329
|
+
);
|
|
13330
|
+
addCompleteCallback((data, outcomeEvent) =>
|
|
13331
|
+
sideEffect({ data }, outcomeEvent),
|
|
13332
|
+
);
|
|
13319
13333
|
return;
|
|
13320
13334
|
}
|
|
13321
13335
|
const { abort, error, complete } = sideEffect;
|
|
@@ -13323,56 +13337,6 @@ const useExecuteAction = (
|
|
|
13323
13337
|
addErrorCallback(error);
|
|
13324
13338
|
addCompleteCallback(complete);
|
|
13325
13339
|
};
|
|
13326
|
-
addSideEffect({
|
|
13327
|
-
abort: (reason) => {
|
|
13328
|
-
const element = elementRef.current;
|
|
13329
|
-
if (
|
|
13330
|
-
// at this stage the action side effect might have removed the <element> from the DOM
|
|
13331
|
-
// (in theory no because action side effect are batched to happen after)
|
|
13332
|
-
// but other side effects might do this
|
|
13333
|
-
element
|
|
13334
|
-
) {
|
|
13335
|
-
dispatchInternalCustomEvent(element, "navi_action_abort", {
|
|
13336
|
-
...sharedActionEventDetail,
|
|
13337
|
-
reason,
|
|
13338
|
-
});
|
|
13339
|
-
}
|
|
13340
|
-
},
|
|
13341
|
-
error: (error) => {
|
|
13342
|
-
if (errorEffect === "show_validation_message") {
|
|
13343
|
-
addErrorMessage(error, { requester });
|
|
13344
|
-
} else if (errorEffect === "throw") {
|
|
13345
|
-
setError(error);
|
|
13346
|
-
}
|
|
13347
|
-
|
|
13348
|
-
const element = elementRef.current;
|
|
13349
|
-
if (
|
|
13350
|
-
// at this stage the action side effect might have removed the <element> from the DOM
|
|
13351
|
-
// (in theory no because action side effect are batched to happen after)
|
|
13352
|
-
// but other side effects might do this
|
|
13353
|
-
element
|
|
13354
|
-
) {
|
|
13355
|
-
dispatchInternalCustomEvent(element, "navi_action_error", {
|
|
13356
|
-
...sharedActionEventDetail,
|
|
13357
|
-
error,
|
|
13358
|
-
});
|
|
13359
|
-
}
|
|
13360
|
-
},
|
|
13361
|
-
complete: (data) => {
|
|
13362
|
-
const element = elementRef.current;
|
|
13363
|
-
if (
|
|
13364
|
-
// at this stage the action side effect might have removed the <element> from the DOM
|
|
13365
|
-
// (in theory no because action side effect are batched to happen after)
|
|
13366
|
-
// but other side effects might do this
|
|
13367
|
-
element
|
|
13368
|
-
) {
|
|
13369
|
-
dispatchInternalCustomEvent(element, "navi_action_end", {
|
|
13370
|
-
...sharedActionEventDetail,
|
|
13371
|
-
data,
|
|
13372
|
-
});
|
|
13373
|
-
}
|
|
13374
|
-
},
|
|
13375
|
-
});
|
|
13376
13340
|
|
|
13377
13341
|
const actionStartEventDetail = {
|
|
13378
13342
|
...sharedActionEventDetail,
|
|
@@ -13384,13 +13348,50 @@ const useExecuteAction = (
|
|
|
13384
13348
|
actionStartEventDetail,
|
|
13385
13349
|
);
|
|
13386
13350
|
|
|
13351
|
+
// The outcome is told twice: to the element, when there still is one,
|
|
13352
|
+
// and to the side effects registered at navi_action_start, always. A
|
|
13353
|
+
// run can outlive its control — the run's own answer, written to a
|
|
13354
|
+
// store the parent reads to decide what it draws, unmounts the control
|
|
13355
|
+
// one microtask before the run settles — and the element is then no
|
|
13356
|
+
// place to dispatch to: Preact drops a detached element's listeners.
|
|
13357
|
+
// The side effects are the run's, not the element's, so the event
|
|
13358
|
+
// reaches them either way.
|
|
13359
|
+
const tellOutcome = (outcomeEventName, outcomeEventDetail, trigger) => {
|
|
13360
|
+
const outcomeEvent = createInternalCustomEvent(outcomeEventName, {
|
|
13361
|
+
...sharedActionEventDetail,
|
|
13362
|
+
...outcomeEventDetail,
|
|
13363
|
+
});
|
|
13364
|
+
const element = elementRef.current;
|
|
13365
|
+
if (element) {
|
|
13366
|
+
element.dispatchEvent(outcomeEvent);
|
|
13367
|
+
}
|
|
13368
|
+
trigger(outcomeEvent);
|
|
13369
|
+
};
|
|
13370
|
+
|
|
13387
13371
|
const runAction = () => {
|
|
13388
13372
|
return action[method]({
|
|
13389
13373
|
event: actionEvent,
|
|
13390
13374
|
reason: `"${event.type}" event on ${getElementSignature(event.target)}`,
|
|
13391
|
-
onAbort:
|
|
13392
|
-
|
|
13393
|
-
|
|
13375
|
+
onAbort: (reason) => {
|
|
13376
|
+
tellOutcome("navi_action_abort", { reason }, (outcomeEvent) => {
|
|
13377
|
+
triggerAbort(reason, outcomeEvent);
|
|
13378
|
+
});
|
|
13379
|
+
},
|
|
13380
|
+
onError: (error) => {
|
|
13381
|
+
if (errorEffect === "show_validation_message") {
|
|
13382
|
+
addErrorMessage(error, { requester });
|
|
13383
|
+
} else if (errorEffect === "throw") {
|
|
13384
|
+
setError(error);
|
|
13385
|
+
}
|
|
13386
|
+
tellOutcome("navi_action_error", { error }, (outcomeEvent) => {
|
|
13387
|
+
triggerError(error, outcomeEvent);
|
|
13388
|
+
});
|
|
13389
|
+
},
|
|
13390
|
+
onComplete: (data) => {
|
|
13391
|
+
tellOutcome("navi_action_end", { data }, (outcomeEvent) => {
|
|
13392
|
+
triggerComplete(data, outcomeEvent);
|
|
13393
|
+
});
|
|
13394
|
+
},
|
|
13394
13395
|
});
|
|
13395
13396
|
};
|
|
13396
13397
|
|
|
@@ -32476,8 +32477,26 @@ const resolveExplicitTarget = (element) => {
|
|
|
32476
32477
|
}
|
|
32477
32478
|
return undefined;
|
|
32478
32479
|
};
|
|
32480
|
+
// The control around the source that a command can be about: one holding a
|
|
32481
|
+
// value of its own. A popup is a control root too (it answers interactions,
|
|
32482
|
+
// carries a callout), but it has no host of its own — asked for one, it
|
|
32483
|
+
// answers with the first control INSIDE it, which for a field sending
|
|
32484
|
+
// --navi-update from a picker's popup is that very field: the command then
|
|
32485
|
+
// sets the field to what it already holds, which fires the command again,
|
|
32486
|
+
// without end. Such a surface is walked past, up to the picker or the form.
|
|
32479
32487
|
const resolveFirstParentControl = (el) => {
|
|
32480
|
-
|
|
32488
|
+
let parentControl = getParentControl(el);
|
|
32489
|
+
while (parentControl && !ownsControlHost(parentControl)) {
|
|
32490
|
+
parentControl = getParentControl(parentControl);
|
|
32491
|
+
}
|
|
32492
|
+
return parentControl;
|
|
32493
|
+
};
|
|
32494
|
+
const ownsControlHost = (controlRoot) => {
|
|
32495
|
+
const controlHost = findControlHost(controlRoot);
|
|
32496
|
+
return (
|
|
32497
|
+
Boolean(controlHost) &&
|
|
32498
|
+
controlHost.closest("[navi-control]") === controlRoot
|
|
32499
|
+
);
|
|
32481
32500
|
};
|
|
32482
32501
|
const resolveFirstChildControl = (el) => {
|
|
32483
32502
|
let startEl;
|
|
@@ -35278,6 +35297,21 @@ const warnPopupHasNoElementToOpen = (popupKind) => {
|
|
|
35278
35297
|
*/
|
|
35279
35298
|
const OUTSIDE_REGION_ATTRIBUTE = "data-navi-popup-outside";
|
|
35280
35299
|
|
|
35300
|
+
/**
|
|
35301
|
+
* `data-navi-popup-inside` is the other direction: a box of the PAGE the
|
|
35302
|
+
* caller says belongs to a popup, so a press on it is not outside that popup
|
|
35303
|
+
* even though it lies beyond the border box — a card whose press is what
|
|
35304
|
+
* fills the one panel of a board. Its value names the popup by `id`, the way
|
|
35305
|
+
* `commandfor` does (several ids, space separated), because the exemption is
|
|
35306
|
+
* one popup's: a menu open beside the board still closes on the same press.
|
|
35307
|
+
*
|
|
35308
|
+
* Unlike the outside marker it answers for its whole subtree: the outside
|
|
35309
|
+
* marker carves free space out of a surface whose controls stay surface, this
|
|
35310
|
+
* one adds a whole thing — the card, its count, its buttons — to the popup's
|
|
35311
|
+
* own ground, and nothing in it is a dismissal.
|
|
35312
|
+
*/
|
|
35313
|
+
const INSIDE_ATTRIBUTE = "data-navi-popup-inside";
|
|
35314
|
+
|
|
35281
35315
|
/**
|
|
35282
35316
|
* What a press landing on a region the caller declared as not-its-surface
|
|
35283
35317
|
* does: exactly what the same press on the backdrop would do.
|
|
@@ -35424,6 +35458,14 @@ const armOutsidePressClose = (
|
|
|
35424
35458
|
) {
|
|
35425
35459
|
return;
|
|
35426
35460
|
}
|
|
35461
|
+
if (
|
|
35462
|
+
popupEl.id &&
|
|
35463
|
+
pointerDownEvent.target.closest?.(
|
|
35464
|
+
`[${INSIDE_ATTRIBUTE}~="${CSS.escape(popupEl.id)}"]`,
|
|
35465
|
+
)
|
|
35466
|
+
) {
|
|
35467
|
+
return;
|
|
35468
|
+
}
|
|
35427
35469
|
// Real DOM containment wins over the rectangle below — an element
|
|
35428
35470
|
// genuinely inside the popup (`overflow: visible`, a negative margin, an
|
|
35429
35471
|
// absolutely-positioned child) can be painted outside its border box, and
|
|
@@ -40869,10 +40911,24 @@ const useInteractiveProps = (props, {
|
|
|
40869
40911
|
// aborted run, whose promise is awaited to completion (see
|
|
40870
40912
|
// performRun in actions.js) — which is exactly what "the server is
|
|
40871
40913
|
// done with it" means, and therefore when the queued request may go.
|
|
40872
|
-
e.detail.addSideEffect(outcome => {
|
|
40914
|
+
e.detail.addSideEffect((outcome, outcomeEvent) => {
|
|
40873
40915
|
uiStateController.actionInFlight = false;
|
|
40874
40916
|
uiStateController.runningActionSignal.value = null;
|
|
40875
40917
|
uiStateController.parallelGuard?.release(uiStateController);
|
|
40918
|
+
// The outcome callbacks are told from here, the run's side effect,
|
|
40919
|
+
// and not from the onnavi_action_* handlers below: the run can
|
|
40920
|
+
// outlive this control (its own answer, written to a store the
|
|
40921
|
+
// parent reads, unmounts it one microtask before it settles), and
|
|
40922
|
+
// whoever wears the run — a parent's `loading` following these,
|
|
40923
|
+
// see 12_picker_card_demo.html — must hear it end all the same.
|
|
40924
|
+
// The handlers below keep what needs the element.
|
|
40925
|
+
if (outcome.aborted) {
|
|
40926
|
+
onActionAborted?.(outcomeEvent);
|
|
40927
|
+
} else if ("error" in outcome) {
|
|
40928
|
+
onActionError?.(outcome.error, outcomeEvent);
|
|
40929
|
+
} else {
|
|
40930
|
+
onActionEnd?.(outcome.data, outcomeEvent);
|
|
40931
|
+
}
|
|
40876
40932
|
const queuedEvent = uiStateController.queuedActionAllowedEvent;
|
|
40877
40933
|
if (!queuedEvent) {
|
|
40878
40934
|
syncOptimisticAttribute(false);
|
|
@@ -40912,7 +40968,6 @@ const useInteractiveProps = (props, {
|
|
|
40912
40968
|
if (resetOnAbort && !superseded) {
|
|
40913
40969
|
dispatchRequestResetUIState(e.currentTarget, e);
|
|
40914
40970
|
}
|
|
40915
|
-
onActionAborted?.(e);
|
|
40916
40971
|
},
|
|
40917
40972
|
onnavi_action_error: e => {
|
|
40918
40973
|
const {
|
|
@@ -40922,7 +40977,6 @@ const useInteractiveProps = (props, {
|
|
|
40922
40977
|
if (resetOnError) {
|
|
40923
40978
|
dispatchRequestResetUIState(e.currentTarget, e);
|
|
40924
40979
|
}
|
|
40925
|
-
onActionError?.(error, e);
|
|
40926
40980
|
uiStateController.onActionError(e);
|
|
40927
40981
|
},
|
|
40928
40982
|
onnavi_action_end: e => {
|
|
@@ -40930,7 +40984,6 @@ const useInteractiveProps = (props, {
|
|
|
40930
40984
|
data
|
|
40931
40985
|
} = e.detail;
|
|
40932
40986
|
debugAction(e, `action end with data: ${JSON.stringify(data)}`);
|
|
40933
|
-
onActionEnd?.(data, e);
|
|
40934
40987
|
controlRootProps.onnavi_action_end?.(e);
|
|
40935
40988
|
uiStateController.onActionEnd(e);
|
|
40936
40989
|
|
|
@@ -48844,33 +48897,6 @@ const createToggleEvent = open => {
|
|
|
48844
48897
|
return toggleEvent;
|
|
48845
48898
|
};
|
|
48846
48899
|
|
|
48847
|
-
const NextResolverContext = createContext(null);
|
|
48848
|
-
const useNextResolver = () => useContext(NextResolverContext);
|
|
48849
|
-
|
|
48850
|
-
/**
|
|
48851
|
-
* Creates a renderComponent function that passes props through a chain of resolvers.
|
|
48852
|
-
* Each resolver is a Preact component rendered in sequence (hooks are allowed).
|
|
48853
|
-
* To pass through to the next resolver, call useNextResolver() and render the
|
|
48854
|
-
* returned Next component with the desired props.
|
|
48855
|
-
* To terminate the chain early (e.g. render a specialized component), render
|
|
48856
|
-
* directly without calling Next.
|
|
48857
|
-
*
|
|
48858
|
-
* The last entry in the array is the final/target component — it receives null
|
|
48859
|
-
* from useNextResolver() indicating it is terminal.
|
|
48860
|
-
*
|
|
48861
|
-
* Usage:
|
|
48862
|
-
* const renderButton = createComponentResolver([ResolverA, ResolverB, ButtonTarget]);
|
|
48863
|
-
* // Then inside a component render:
|
|
48864
|
-
* renderButton(props)
|
|
48865
|
-
*
|
|
48866
|
-
* Each position of the chain has a runner of its own, defined once: it renders
|
|
48867
|
-
* its resolver under a NextResolverContext holding the runner after it. A
|
|
48868
|
-
* resolver that re-renders on its own and renders <Next> therefore resumes at
|
|
48869
|
-
* its own position without any bookkeeping — the Next it was given is the one
|
|
48870
|
-
* made for it. A chain rendered by the hundred (a list's rows) pays two
|
|
48871
|
-
* components per position, the runner and the resolver, so nothing here is a
|
|
48872
|
-
* component that merely forwards.
|
|
48873
|
-
*/
|
|
48874
48900
|
const createComponentResolver = (resolvers, {
|
|
48875
48901
|
pure
|
|
48876
48902
|
} = {}) => {
|
|
@@ -48879,13 +48905,10 @@ const createComponentResolver = (resolvers, {
|
|
|
48879
48905
|
for (let index = 0; index < resolvers.length; index++) {
|
|
48880
48906
|
const Resolver = resolvers[index];
|
|
48881
48907
|
const isLast = index === lastIndex;
|
|
48882
|
-
|
|
48883
|
-
|
|
48884
|
-
|
|
48885
|
-
|
|
48886
|
-
})
|
|
48887
|
-
});
|
|
48888
|
-
Runner.displayName = `${Resolver.displayName || Resolver.name}Runner`;
|
|
48908
|
+
function Runner(props) {
|
|
48909
|
+
return runResolverBody(this, Resolver, props, isLast ? null : runners[index + 1]);
|
|
48910
|
+
}
|
|
48911
|
+
Runner.displayName = Resolver.displayName || Resolver.name;
|
|
48889
48912
|
runners.push(Runner);
|
|
48890
48913
|
}
|
|
48891
48914
|
const FirstRunner = runners[0];
|
|
@@ -48916,6 +48939,54 @@ const createComponentResolver = (resolvers, {
|
|
|
48916
48939
|
}
|
|
48917
48940
|
return PureRenderComponent;
|
|
48918
48941
|
};
|
|
48942
|
+
const useNextResolver = () => {
|
|
48943
|
+
if (currentNext === OUTSIDE_RESOLVER_BODY) {
|
|
48944
|
+
throw new Error("useNextResolver() called outside a resolver body: a resolver rendered by another resolver is rendered with renderResolver(Resolver, props), not as a JSX child.");
|
|
48945
|
+
}
|
|
48946
|
+
return currentNext;
|
|
48947
|
+
};
|
|
48948
|
+
const renderResolver = (Resolver, props) => {
|
|
48949
|
+
if (currentNext === OUTSIDE_RESOLVER_BODY) {
|
|
48950
|
+
throw new Error(`renderResolver(${Resolver.displayName || Resolver.name}) called outside a resolver body: only a resolver can render another one.`);
|
|
48951
|
+
}
|
|
48952
|
+
let SubRunner = subRunnerByResolver.get(Resolver);
|
|
48953
|
+
if (!SubRunner) {
|
|
48954
|
+
SubRunner = function (props) {
|
|
48955
|
+
const {
|
|
48956
|
+
[NEXT_PROP]: next,
|
|
48957
|
+
...ownProps
|
|
48958
|
+
} = props;
|
|
48959
|
+
return runResolverBody(this, Resolver, ownProps, next);
|
|
48960
|
+
};
|
|
48961
|
+
SubRunner.displayName = Resolver.displayName || Resolver.name;
|
|
48962
|
+
subRunnerByResolver.set(Resolver, SubRunner);
|
|
48963
|
+
}
|
|
48964
|
+
return createElement(SubRunner, {
|
|
48965
|
+
...props,
|
|
48966
|
+
[NEXT_PROP]: currentNext
|
|
48967
|
+
});
|
|
48968
|
+
};
|
|
48969
|
+
|
|
48970
|
+
// What useNextResolver() answers: the runner after the one whose body is
|
|
48971
|
+
// running, null for the last — and, outside any body, a value that is neither.
|
|
48972
|
+
const OUTSIDE_RESOLVER_BODY = Symbol("outside_resolver_body");
|
|
48973
|
+
let currentNext = OUTSIDE_RESOLVER_BODY;
|
|
48974
|
+
const runResolverBody = (instance, Resolver, props, next) => {
|
|
48975
|
+
const nextBefore = currentNext;
|
|
48976
|
+
currentNext = next;
|
|
48977
|
+
try {
|
|
48978
|
+
return Resolver.call(instance, props);
|
|
48979
|
+
} finally {
|
|
48980
|
+
currentNext = nextBefore;
|
|
48981
|
+
}
|
|
48982
|
+
};
|
|
48983
|
+
|
|
48984
|
+
// One runner per resolver rendered through renderResolver, made on first use:
|
|
48985
|
+
// the same component type on every render, so a resolver picked again is
|
|
48986
|
+
// updated in place and another one picked is a remount, like any child.
|
|
48987
|
+
const subRunnerByResolver = new WeakMap();
|
|
48988
|
+
// Rides on the props of a sub-runner, stripped before the body sees them.
|
|
48989
|
+
const NEXT_PROP = "navi-resolver-next";
|
|
48919
48990
|
function pureShouldComponentUpdate(nextProps) {
|
|
48920
48991
|
return shallowDiffers(this.props, nextProps);
|
|
48921
48992
|
}
|
|
@@ -49741,9 +49812,7 @@ const ButtonConfirm = ({
|
|
|
49741
49812
|
const ButtonRouteResolver = props => {
|
|
49742
49813
|
const Next = useNextResolver();
|
|
49743
49814
|
if (props.route) {
|
|
49744
|
-
return
|
|
49745
|
-
...props
|
|
49746
|
-
});
|
|
49815
|
+
return renderResolver(ButtonWithRoute, props);
|
|
49747
49816
|
}
|
|
49748
49817
|
return jsx(Next, {
|
|
49749
49818
|
...props
|
|
@@ -52347,9 +52416,7 @@ const installInputCss = () => {
|
|
|
52347
52416
|
const InputModeResolver = props => {
|
|
52348
52417
|
const Next = useNextResolver();
|
|
52349
52418
|
if (props.inputMode === "numeric" || props.inputMode === "decimal") {
|
|
52350
|
-
return
|
|
52351
|
-
...props
|
|
52352
|
-
});
|
|
52419
|
+
return renderResolver(InputModeNumericOrDecimal, props);
|
|
52353
52420
|
}
|
|
52354
52421
|
return jsx(Next, {
|
|
52355
52422
|
...props
|
|
@@ -52577,39 +52644,25 @@ const InputTypeResolver = props => {
|
|
|
52577
52644
|
// very same "icon while empty, clear button once filled" affordance without
|
|
52578
52645
|
// pretending to be a search box.
|
|
52579
52646
|
if (props.clearable && props.type !== "search") {
|
|
52580
|
-
return
|
|
52581
|
-
...props
|
|
52582
|
-
});
|
|
52647
|
+
return renderResolver(InputClearable, props);
|
|
52583
52648
|
}
|
|
52584
52649
|
if (props.type === "search") {
|
|
52585
|
-
return
|
|
52586
|
-
...props
|
|
52587
|
-
});
|
|
52650
|
+
return renderResolver(InputSearch, props);
|
|
52588
52651
|
}
|
|
52589
52652
|
if (props.type === "email") {
|
|
52590
|
-
return
|
|
52591
|
-
...props
|
|
52592
|
-
});
|
|
52653
|
+
return renderResolver(InputEmail, props);
|
|
52593
52654
|
}
|
|
52594
52655
|
if (props.type === "tel") {
|
|
52595
|
-
return
|
|
52596
|
-
...props
|
|
52597
|
-
});
|
|
52656
|
+
return renderResolver(InputTel, props);
|
|
52598
52657
|
}
|
|
52599
52658
|
if (props.type === "number") {
|
|
52600
|
-
return
|
|
52601
|
-
...props
|
|
52602
|
-
});
|
|
52659
|
+
return renderResolver(InputNumber, props);
|
|
52603
52660
|
}
|
|
52604
52661
|
if (props.type === "color") {
|
|
52605
|
-
return
|
|
52606
|
-
...props
|
|
52607
|
-
});
|
|
52662
|
+
return renderResolver(InputColor, props);
|
|
52608
52663
|
}
|
|
52609
52664
|
if (props.type === "datetime-local") {
|
|
52610
|
-
return
|
|
52611
|
-
...props
|
|
52612
|
-
});
|
|
52665
|
+
return renderResolver(InputDatetimeLocal, props);
|
|
52613
52666
|
}
|
|
52614
52667
|
return jsx(Next, {
|
|
52615
52668
|
...props
|
|
@@ -52722,9 +52775,7 @@ const InputDatetimeLocal = props => {
|
|
|
52722
52775
|
const InputWithListResolver = props => {
|
|
52723
52776
|
const Next = useNextResolver();
|
|
52724
52777
|
if (props["navi-list"]) {
|
|
52725
|
-
return
|
|
52726
|
-
...props
|
|
52727
|
-
});
|
|
52778
|
+
return renderResolver(InputWithList, props);
|
|
52728
52779
|
}
|
|
52729
52780
|
return jsx(Next, {
|
|
52730
52781
|
...props
|
|
@@ -52831,9 +52882,7 @@ const ChevronDownSvg$1 = () => {
|
|
|
52831
52882
|
const InputWithSuggestionsResolver = props => {
|
|
52832
52883
|
const Next = useNextResolver();
|
|
52833
52884
|
if (props["navi-suggestions"]) {
|
|
52834
|
-
return
|
|
52835
|
-
...props
|
|
52836
|
-
});
|
|
52885
|
+
return renderResolver(InputTextualWithSuggestions, props);
|
|
52837
52886
|
}
|
|
52838
52887
|
return jsx(Next, {
|
|
52839
52888
|
...props
|
|
@@ -60414,34 +60463,44 @@ const css$E = /* css */`
|
|
|
60414
60463
|
* `showModal()`'d (native focus trap, `Escape`-to-cancel, hardware
|
|
60415
60464
|
* back-button dismissal, rest-of-document made inert), without one it is
|
|
60416
60465
|
* shown through the Popover API and the page behind stays live.
|
|
60417
|
-
* @param {boolean} [props.dockedOnSmallTouchScreen] - Turns
|
|
60418
|
-
*
|
|
60419
|
-
* screen, and leaves it alone otherwise
|
|
60420
|
-
*
|
|
60421
|
-
* the
|
|
60422
|
-
*
|
|
60423
|
-
*
|
|
60424
|
-
*
|
|
60425
|
-
*
|
|
60426
|
-
*
|
|
60427
|
-
*
|
|
60428
|
-
*
|
|
60466
|
+
* @param {boolean|"top"|"bottom"} [props.dockedOnSmallTouchScreen] - Turns
|
|
60467
|
+
* the dialog into a sheet (docked flush to one edge, full width) on a small
|
|
60468
|
+
* touch screen, and leaves it alone otherwise: under a mouse the centered box
|
|
60469
|
+
* is already the right shape, while on a phone a centered box ends up cramped
|
|
60470
|
+
* between the keyboard and the top of the screen. The value says which edge
|
|
60471
|
+
* the sheet rests on. `true` (or `"top"`) rests it on the top edge, out of
|
|
60472
|
+
* the virtual keyboard's way: a field tapped in the sheet raises the keyboard
|
|
60473
|
+
* below it, and the question and the field stay where the finger found them.
|
|
60474
|
+
* `"bottom"` rests it on the bottom edge, where the thumbs are — for a sheet
|
|
60475
|
+
* that is read and tapped (a list, a couple of buttons, a confirmation) and
|
|
60476
|
+
* holds nothing that raises a keyboard; one that does is reflowed into the
|
|
60477
|
+
* strip left above the keyboard at every keystroke. The edge is said here
|
|
60478
|
+
* rather than through `positionArea`, which places both shapes:
|
|
60479
|
+
* `positionArea="bottom"` would also pin the centered box to the bottom of a
|
|
60480
|
+
* desktop window. Both halves of the name matter (`smallTouchScreenSignal`):
|
|
60481
|
+
* touch alone would dock a big touch screen — a tablet, a kiosk panel — a
|
|
60482
|
+
* whole screen away from where the finger just tapped, and size alone would
|
|
60483
|
+
* dock a narrow desktop window, which is still a mouse. It supplies defaults
|
|
60484
|
+
* for `positionArea`, `marginWithContainer`, `expandX` and `scrollCapture`,
|
|
60485
|
+
* so any of them can still be pinned explicitly — including `expandX={false}`,
|
|
60429
60486
|
* which opts the docked dialog out of the full-width stretch and leaves it a
|
|
60430
|
-
* floating box
|
|
60487
|
+
* floating box against its edge. It also withdraws `maxWidth` while docked: a
|
|
60431
60488
|
* sheet is container-wide by definition, and a `maxWidth` is an answer about
|
|
60432
60489
|
* the *centered* shape, so the two can be stated together (`maxWidth="16rem"
|
|
60433
60490
|
* dockedOnSmallTouchScreen`) and each applies where it means something.
|
|
60434
60491
|
* `minWidth` needs no such rule — its floor is below the full width — and
|
|
60435
60492
|
* `maxHeight`/`minHeight` keep applying, a sheet being content-tall.
|
|
60436
|
-
* Ignored entirely when `expandY`
|
|
60437
|
-
*
|
|
60438
|
-
*
|
|
60439
|
-
*
|
|
60440
|
-
*
|
|
60441
|
-
*
|
|
60442
|
-
*
|
|
60443
|
-
*
|
|
60444
|
-
*
|
|
60493
|
+
* Ignored entirely when `expandY` (or `expand`) is set: a dialog already
|
|
60494
|
+
* filling the height touches both edges, so docking could only take away the
|
|
60495
|
+
* shape the caller asked for. Re-resolves live as the pointer type or the
|
|
60496
|
+
* window size changes. A sheet is also pushed back through the edge it rests
|
|
60497
|
+
* on to close it (down for a bottom sheet, up for a top one), held by its
|
|
60498
|
+
* header (a `Box` with the `header` prop) and by anything else carrying
|
|
60499
|
+
* `data-swipe-grip`. The rest of the sheet is left to what it holds, so a
|
|
60500
|
+
* board something is dragged across keeps its own gestures. See
|
|
60501
|
+
* `swipe_to_close.js`. In dev, a `"bottom"` sheet found holding a field that
|
|
60502
|
+
* raises the keyboard is warned about at open, on any screen — the mistake
|
|
60503
|
+
* itself only shows on a phone.
|
|
60445
60504
|
* @param {string} [props.positionArea="center"] - Where to dock the dialog
|
|
60446
60505
|
* within its container (the viewport for `layer="top"`, the positioned
|
|
60447
60506
|
* ancestor for `layer="local"`) — Dialog is never anchored to a real
|
|
@@ -60809,28 +60868,28 @@ const DialogLocal = props => {
|
|
|
60809
60868
|
* own to render: a modal's is the native `::backdrop`, and `backdrop={false}`
|
|
60810
60869
|
* has none at all.
|
|
60811
60870
|
*/
|
|
60812
|
-
// What a dialog turns into on a small touch screen
|
|
60813
|
-
//
|
|
60814
|
-
//
|
|
60815
|
-
//
|
|
60871
|
+
// What a dialog turns into on a small touch screen: a sheet flush against one
|
|
60872
|
+
// edge of the screen. Which edge is the caller's word (the prop's value, see
|
|
60873
|
+
// its JSDoc), the top one unless told "bottom": the cheap mistake must be the
|
|
60874
|
+
// default one — a sheet docked top by mistake is a little farther from the
|
|
60875
|
+
// thumb, a sheet docked bottom by mistake fights the virtual keyboard, which
|
|
60876
|
+
// rises from that very edge, on every keystroke.
|
|
60816
60877
|
// Only defaults: an explicitly passed prop still wins, so the docked shape can
|
|
60817
60878
|
// be adjusted one axis at a time instead of being all-or-nothing.
|
|
60818
60879
|
const DOCKED = {
|
|
60819
|
-
positionArea: "bottom",
|
|
60820
60880
|
marginWithContainer: 0,
|
|
60821
60881
|
expandX: true,
|
|
60822
|
-
// A sheet
|
|
60823
|
-
//
|
|
60824
|
-
// reasoning as "bottom" above, applied to the gesture instead of the shape.
|
|
60882
|
+
// A sheet is dragged with a thumb, and a drag that runs past its own edge
|
|
60883
|
+
// must not land on the page behind it.
|
|
60825
60884
|
scrollCapture: true
|
|
60826
60885
|
};
|
|
60827
60886
|
|
|
60828
|
-
// Where a
|
|
60829
|
-
// with `header`, plus anything the application marked as one more.
|
|
60830
|
-
// else in the sheet is content the finger came to operate — a board
|
|
60831
|
-
// dragged across, a list, a map — and a press there belongs to it. A
|
|
60832
|
-
// no header and nothing marked is not pushed
|
|
60833
|
-
// own controls, by the backdrop and by Escape.
|
|
60887
|
+
// Where a sheet is held to push it back through its edge: the strip a Box
|
|
60888
|
+
// declares with `header`, plus anything the application marked as one more.
|
|
60889
|
+
// Everything else in the sheet is content the finger came to operate — a board
|
|
60890
|
+
// a piece is dragged across, a list, a map — and a press there belongs to it. A
|
|
60891
|
+
// sheet with no header and nothing marked is not pushed back at all; it is
|
|
60892
|
+
// closed by its own controls, by the backdrop and by Escape.
|
|
60834
60893
|
const DOCKED_SWIPE_GRIP = "[data-header],[data-swipe-grip]";
|
|
60835
60894
|
const useDialogProps = props => {
|
|
60836
60895
|
const backdropProps = {};
|
|
@@ -60936,12 +60995,15 @@ const useDialogProps = props => {
|
|
|
60936
60995
|
// Only a small touch screen changes anything: on a mouse — and on a touch
|
|
60937
60996
|
// screen too big to reach the bottom edge of — a dialog already wants to be
|
|
60938
60997
|
// the centered box it is by default, so there is nothing to resolve.
|
|
60939
|
-
// expandY cancels the docking outright:
|
|
60940
|
-
//
|
|
60941
|
-
//
|
|
60942
|
-
// caller asked for (and arm a swipe-down on something that never rose).
|
|
60998
|
+
// expandY cancels the docking outright: a dialog already filling the height
|
|
60999
|
+
// touches both edges — all docking could still do is take away the shape
|
|
61000
|
+
// the caller asked for (and arm a swipe on something that never rose).
|
|
60943
61001
|
const isDocked = dockedOnSmallTouchScreen && smallTouchScreenSignal.value && !expandY;
|
|
60944
|
-
const
|
|
61002
|
+
const dockedEdge = dockedOnSmallTouchScreen === "bottom" ? "bottom" : "top";
|
|
61003
|
+
const positionArea = positionAreaProp ?? (isDocked ? dockedEdge : "center");
|
|
61004
|
+
// Read off the shape a phone would give, not the one this screen gives: the
|
|
61005
|
+
// author of a bottom sheet tests on a desktop, where the mistake is silent.
|
|
61006
|
+
const sheetRestsOnBottom = Boolean(dockedOnSmallTouchScreen) && !expandY && restsOnBottom(positionAreaProp ?? dockedEdge);
|
|
60945
61007
|
const marginWithContainer = marginWithContainerProp ?? (isDocked ? DOCKED.marginWithContainer :
|
|
60946
61008
|
// A share of whatever holds the dialog: the app's own screen for a
|
|
60947
61009
|
// top-layer one — where appw is exactly "3% of the container", the
|
|
@@ -61003,12 +61065,12 @@ const useDialogProps = props => {
|
|
|
61003
61065
|
y: "center",
|
|
61004
61066
|
x: "center"
|
|
61005
61067
|
};
|
|
61006
|
-
// Pushing the sheet back
|
|
61007
|
-
//
|
|
61008
|
-
// actually resting on
|
|
61009
|
-
//
|
|
61010
|
-
const
|
|
61011
|
-
const onSwipePointerDown =
|
|
61068
|
+
// Pushing the sheet back through the edge it rests on closes it — the way
|
|
61069
|
+
// it came in, and the way the thumb on that edge already pushes. Only a sheet
|
|
61070
|
+
// actually resting on an edge: anywhere else the gesture would send the
|
|
61071
|
+
// dialog somewhere it never came from.
|
|
61072
|
+
const swipeToCloseSide = isDocked && (parsedPositionArea.y === "top" || parsedPositionArea.y === "bottom") ? parsedPositionArea.y : null;
|
|
61073
|
+
const onSwipePointerDown = swipeToCloseSide ? createSwipeToClose(swipeToCloseSide, {
|
|
61012
61074
|
grip: DOCKED_SWIPE_GRIP
|
|
61013
61075
|
}) : null;
|
|
61014
61076
|
// A corner sitting exactly on the container's own corner must not be
|
|
@@ -61136,6 +61198,9 @@ const useDialogProps = props => {
|
|
|
61136
61198
|
}
|
|
61137
61199
|
{
|
|
61138
61200
|
warnAboutUnreachableOutsideRegions(dialogEl);
|
|
61201
|
+
if (sheetRestsOnBottom) {
|
|
61202
|
+
warnBottomSheetHoldingKeyboardControl(dialogEl);
|
|
61203
|
+
}
|
|
61139
61204
|
}
|
|
61140
61205
|
|
|
61141
61206
|
// Set by useOpenControllerByProps for the very first open triggered by
|
|
@@ -61684,12 +61749,12 @@ const useDialogProps = props => {
|
|
|
61684
61749
|
"data-flush-right": flushEdges.right ? "" : undefined,
|
|
61685
61750
|
"data-flush-bottom": flushEdges.bottom ? "" : undefined,
|
|
61686
61751
|
"data-flush-left": flushEdges.left ? "" : undefined,
|
|
61687
|
-
"data-swipe-to-close":
|
|
61752
|
+
"data-swipe-to-close": swipeToCloseSide ?? undefined,
|
|
61688
61753
|
// The axis the sheet travels on when it is pushed back, said to the shared
|
|
61689
61754
|
// gesture layer: it is what a box travelling inside the sheet reads to know
|
|
61690
61755
|
// this axis is already walked (see @jsenv/dom's drag_to_travel).
|
|
61691
|
-
"data-drag-travel":
|
|
61692
|
-
"data-travel-by-drag":
|
|
61756
|
+
"data-drag-travel": swipeToCloseSide ? SWIPE_AXIS_BY_SIDE[swipeToCloseSide] : undefined,
|
|
61757
|
+
"data-travel-by-drag": swipeToCloseSide ? SWIPE_AXIS_BY_SIDE[swipeToCloseSide] : undefined,
|
|
61693
61758
|
"onPointerDown": e => {
|
|
61694
61759
|
rest.onPointerDown?.(e);
|
|
61695
61760
|
onSwipePointerDown?.(e);
|
|
@@ -61761,6 +61826,33 @@ const useDialogProps = props => {
|
|
|
61761
61826
|
}
|
|
61762
61827
|
return [!isTopLayer && backdrop ? backdropProps : null, contentProps];
|
|
61763
61828
|
};
|
|
61829
|
+
const restsOnBottom = positionArea => {
|
|
61830
|
+
const parsed = parsePositionArea(positionArea);
|
|
61831
|
+
return Boolean(parsed) && parsed.y === "bottom";
|
|
61832
|
+
};
|
|
61833
|
+
|
|
61834
|
+
// What raises a virtual keyboard when tapped: a text-like input, a textarea,
|
|
61835
|
+
// anything editable. Not a `select` — it opens a menu, which takes no screen
|
|
61836
|
+
// from the sheet — and not a read-only field.
|
|
61837
|
+
const KEYBOARD_RAISING_CONTROL_SELECTOR = `
|
|
61838
|
+
input:not([type]):not([readonly]),
|
|
61839
|
+
input[type="text"]:not([readonly]),
|
|
61840
|
+
input[type="search"]:not([readonly]),
|
|
61841
|
+
input[type="email"]:not([readonly]),
|
|
61842
|
+
input[type="url"]:not([readonly]),
|
|
61843
|
+
input[type="tel"]:not([readonly]),
|
|
61844
|
+
input[type="password"]:not([readonly]),
|
|
61845
|
+
input[type="number"]:not([readonly]),
|
|
61846
|
+
textarea:not([readonly]),
|
|
61847
|
+
[contenteditable]:not([contenteditable="false"])
|
|
61848
|
+
`;
|
|
61849
|
+
const warnBottomSheetHoldingKeyboardControl = dialogEl => {
|
|
61850
|
+
const controlEl = dialogEl.querySelector(KEYBOARD_RAISING_CONTROL_SELECTOR);
|
|
61851
|
+
if (!controlEl) {
|
|
61852
|
+
return;
|
|
61853
|
+
}
|
|
61854
|
+
console.warn(`[navi] a Dialog docked to the bottom edge (dockedOnSmallTouchScreen="bottom") holds a field that raises the virtual keyboard. On a phone the keyboard rises from the edge the sheet rests on and reflows the sheet into the strip left above it, at every keystroke. A sheet one types into rests on the top edge: dockedOnSmallTouchScreen without a value. "bottom" is for a sheet one reads and taps.`, controlEl);
|
|
61855
|
+
};
|
|
61764
61856
|
const DIALOG_PSEUDO_CLASSES = [":hover", ":active", ":focus", ":focus-visible", ":focus-within"];
|
|
61765
61857
|
|
|
61766
61858
|
// Lets consumers pass animationDuration="0.5s" as a regular prop; Box maps
|
|
@@ -63492,8 +63584,8 @@ const css$C = /* css */`@layer navi {
|
|
|
63492
63584
|
* @param {string} [props.positionAreaFixed] - **Popover-only**, same guard.
|
|
63493
63585
|
* @param {string} [props.positionAreaWhenAnchorIsInvalid] - **Popover-only**,
|
|
63494
63586
|
* same guard.
|
|
63495
|
-
* @param {boolean} [props.dockedOnSmallTouchScreen] -
|
|
63496
|
-
* popover is never a
|
|
63587
|
+
* @param {boolean|"top"|"bottom"} [props.dockedOnSmallTouchScreen] -
|
|
63588
|
+
* **Dialog-only** (a popover is never a sheet), destructured out for the same reason
|
|
63497
63589
|
* turned around: it must not land on the popover element as a stray DOM
|
|
63498
63590
|
* attribute when the screen-size resolution picks `mode="popover"`. Where
|
|
63499
63591
|
* that resolution lands is what decides whether it applies at all, so a
|
|
@@ -63521,7 +63613,7 @@ const css$C = /* css */`@layer navi {
|
|
|
63521
63613
|
* honoured in either mode — a wall-less `Dialog` is shown through the
|
|
63522
63614
|
* Popover API rather than `showModal()` — so which mode the screen-size
|
|
63523
63615
|
* resolution picks says nothing about whether the page behind stays live.
|
|
63524
|
-
* It is also what makes a sheet docked to
|
|
63616
|
+
* It is also what makes a sheet docked to an edge of a phone's screen
|
|
63525
63617
|
* (`dockedOnSmallTouchScreen`) non-modal.
|
|
63526
63618
|
* @param {"auto"|"discrete"|"invisible"} [props.backdropVariant] - Forwarded
|
|
63527
63619
|
* as-is to whichever component renders (both understand it identically):
|
|
@@ -63717,9 +63809,7 @@ const css$B = /* css */`.navi_picker_callout_dock > [data-picker-content] {
|
|
|
63717
63809
|
const PickerCustomResolver = props => {
|
|
63718
63810
|
import.meta.css = [css$B, "@jsenv/navi/src/control/picker/picker_custom.jsx"];
|
|
63719
63811
|
if (props.children === undefined) {
|
|
63720
|
-
return
|
|
63721
|
-
...props
|
|
63722
|
-
});
|
|
63812
|
+
return renderResolver(PickerNative, props);
|
|
63723
63813
|
}
|
|
63724
63814
|
if (props.mode === "callout") {
|
|
63725
63815
|
// A tooltip is an icon one presses, unless told otherwise. Own-property
|
|
@@ -63781,14 +63871,12 @@ const PickerCustomResolver = props => {
|
|
|
63781
63871
|
// how a field says its value is a JS one, kept beside the DOM (see
|
|
63782
63872
|
// controller_registry.js) — the same thing type="array"/"object" already
|
|
63783
63873
|
// say for their shapes.
|
|
63784
|
-
return
|
|
63874
|
+
return renderResolver(PickerCustom, {
|
|
63785
63875
|
...props,
|
|
63786
63876
|
type: "navi_js"
|
|
63787
63877
|
});
|
|
63788
63878
|
}
|
|
63789
|
-
return
|
|
63790
|
-
...props
|
|
63791
|
-
});
|
|
63879
|
+
return renderResolver(PickerCustom, props);
|
|
63792
63880
|
};
|
|
63793
63881
|
const PickerNative = props => {
|
|
63794
63882
|
const Next = useNextResolver();
|
|
@@ -64414,9 +64502,9 @@ const PickerCustom = props => {
|
|
|
64414
64502
|
});
|
|
64415
64503
|
}
|
|
64416
64504
|
}
|
|
64417
|
-
return
|
|
64505
|
+
return renderResolver(PickerContentInsidePopup, {
|
|
64418
64506
|
...pickerProps,
|
|
64419
|
-
mode
|
|
64507
|
+
mode
|
|
64420
64508
|
});
|
|
64421
64509
|
};
|
|
64422
64510
|
|
|
@@ -65683,14 +65771,10 @@ const createItemTracker = (onChange) => {
|
|
|
65683
65771
|
const ListItemHeaderOrFooterResolver = props => {
|
|
65684
65772
|
const Next = useNextResolver();
|
|
65685
65773
|
if (props.header) {
|
|
65686
|
-
return
|
|
65687
|
-
...props
|
|
65688
|
-
});
|
|
65774
|
+
return renderResolver(ListItemHeader, props);
|
|
65689
65775
|
}
|
|
65690
65776
|
if (props.footer) {
|
|
65691
|
-
return
|
|
65692
|
-
...props
|
|
65693
|
-
});
|
|
65777
|
+
return renderResolver(ListItemFooter, props);
|
|
65694
65778
|
}
|
|
65695
65779
|
return jsx(Next, {
|
|
65696
65780
|
...props
|
|
@@ -65922,9 +66006,7 @@ const ListSelectableContext = createContext(false);
|
|
|
65922
66006
|
const ListSelectableResolver = props => {
|
|
65923
66007
|
const Next = useNextResolver();
|
|
65924
66008
|
if (props.selectable) {
|
|
65925
|
-
return
|
|
65926
|
-
...props
|
|
65927
|
-
});
|
|
66009
|
+
return renderResolver(ListSelectable, props);
|
|
65928
66010
|
}
|
|
65929
66011
|
return jsx(ListSelectableContext.Provider, {
|
|
65930
66012
|
value: false,
|
|
@@ -66224,7 +66306,7 @@ const ListItemSelectableResolver = props => {
|
|
|
66224
66306
|
const isHeaderOrFooter = Boolean(props.header || props.footer);
|
|
66225
66307
|
const selectable = props.selectable ?? (isHeaderOrFooter || props.role === "presentation" ? false : listSelectable);
|
|
66226
66308
|
if (selectable) {
|
|
66227
|
-
return
|
|
66309
|
+
return renderResolver(ListItemSelectable, {
|
|
66228
66310
|
...props,
|
|
66229
66311
|
selectable: true
|
|
66230
66312
|
});
|
|
@@ -71532,14 +71614,10 @@ const generateTimeSlots = (min, max, stepSeconds) => {
|
|
|
71532
71614
|
const PickerPresetResolver = props => {
|
|
71533
71615
|
const Next = useNextResolver();
|
|
71534
71616
|
if (props.type === "navi_time") {
|
|
71535
|
-
return
|
|
71536
|
-
...props
|
|
71537
|
-
});
|
|
71617
|
+
return renderResolver(PickerNaviTime, props);
|
|
71538
71618
|
}
|
|
71539
71619
|
if (props.type === "navi_minute") {
|
|
71540
|
-
return
|
|
71541
|
-
...props
|
|
71542
|
-
});
|
|
71620
|
+
return renderResolver(PickerNaviMinute, props);
|
|
71543
71621
|
}
|
|
71544
71622
|
return jsx(Next, {
|
|
71545
71623
|
...props
|
|
@@ -72337,59 +72415,37 @@ const PencilSvg = () => {
|
|
|
72337
72415
|
const PickerTypeResolver = props => {
|
|
72338
72416
|
const Next = useNextResolver();
|
|
72339
72417
|
if (props.type === "color") {
|
|
72340
|
-
return
|
|
72341
|
-
...props
|
|
72342
|
-
});
|
|
72418
|
+
return renderResolver(PickerColor, props);
|
|
72343
72419
|
}
|
|
72344
72420
|
if (props.type === "datetime") {
|
|
72345
|
-
return
|
|
72346
|
-
...props
|
|
72347
|
-
});
|
|
72421
|
+
return renderResolver(PickerDatetime, props);
|
|
72348
72422
|
}
|
|
72349
72423
|
if (props.type === "date") {
|
|
72350
|
-
return
|
|
72351
|
-
...props
|
|
72352
|
-
});
|
|
72424
|
+
return renderResolver(PickerDate, props);
|
|
72353
72425
|
}
|
|
72354
72426
|
if (props.type === "month") {
|
|
72355
|
-
return
|
|
72356
|
-
...props
|
|
72357
|
-
});
|
|
72427
|
+
return renderResolver(PickerMonth, props);
|
|
72358
72428
|
}
|
|
72359
72429
|
if (props.type === "week") {
|
|
72360
|
-
return
|
|
72361
|
-
...props
|
|
72362
|
-
});
|
|
72430
|
+
return renderResolver(PickerWeek, props);
|
|
72363
72431
|
}
|
|
72364
72432
|
if (props.type === "time") {
|
|
72365
|
-
return
|
|
72366
|
-
...props
|
|
72367
|
-
});
|
|
72433
|
+
return renderResolver(PickerTime, props);
|
|
72368
72434
|
}
|
|
72369
72435
|
if (props.type === "duration") {
|
|
72370
|
-
return
|
|
72371
|
-
...props
|
|
72372
|
-
});
|
|
72436
|
+
return renderResolver(PickerDuration, props);
|
|
72373
72437
|
}
|
|
72374
72438
|
if (props.type === "file") {
|
|
72375
|
-
return
|
|
72376
|
-
...props
|
|
72377
|
-
});
|
|
72439
|
+
return renderResolver(PickerFile, props);
|
|
72378
72440
|
}
|
|
72379
72441
|
if (props.type === "text") {
|
|
72380
|
-
return
|
|
72381
|
-
...props
|
|
72382
|
-
});
|
|
72442
|
+
return renderResolver(PickerText, props);
|
|
72383
72443
|
}
|
|
72384
72444
|
if (props.type === "array") {
|
|
72385
|
-
return
|
|
72386
|
-
...props
|
|
72387
|
-
});
|
|
72445
|
+
return renderResolver(PickerArray, props);
|
|
72388
72446
|
}
|
|
72389
72447
|
if (props.type === "object") {
|
|
72390
|
-
return
|
|
72391
|
-
...props
|
|
72392
|
-
});
|
|
72448
|
+
return renderResolver(PickerObject, props);
|
|
72393
72449
|
}
|
|
72394
72450
|
return jsx(Next, {
|
|
72395
72451
|
...props
|
|
@@ -76812,7 +76868,7 @@ const css$n = /* css */`.navi_split_button {
|
|
|
76812
76868
|
* dialogExpand?: boolean,
|
|
76813
76869
|
* dialogExpandX?: boolean,
|
|
76814
76870
|
* dialogExpandY?: boolean,
|
|
76815
|
-
* dockedOnSmallTouchScreen?: boolean,
|
|
76871
|
+
* dockedOnSmallTouchScreen?: boolean | "top" | "bottom",
|
|
76816
76872
|
* marginWithContainer?: number | string,
|
|
76817
76873
|
* backdrop?: boolean,
|
|
76818
76874
|
* backdropVariant?: "auto" | "discrete" | "invisible",
|
|
@@ -86097,7 +86153,9 @@ const css = /* css */`.navi_side_panel {
|
|
|
86097
86153
|
* closes the panel on an outside click instead, and also enables trapping
|
|
86098
86154
|
* Tab navigation inside the panel (`focusCapture`) — closing on outside
|
|
86099
86155
|
* interaction only makes sense paired with not letting focus silently
|
|
86100
|
-
* leave the panel first.
|
|
86156
|
+
* leave the panel first. A box of the page whose press must not close the
|
|
86157
|
+
* panel (a card that fills it) names the panel:
|
|
86158
|
+
* `data-navi-popup-inside={id}` — see docs/popup_backdrop.md.
|
|
86101
86159
|
* @param {boolean} [props.swipeToClose=true] - Pushing the panel back
|
|
86102
86160
|
* towards the edge it is docked to closes it: the panel follows the
|
|
86103
86161
|
* pointer and finishes leaving (or comes back to rest) when it is
|
|
@@ -86232,6 +86290,7 @@ SidePanel.Foot = SidePanelFoot;
|
|
|
86232
86290
|
|
|
86233
86291
|
const createSlot = (SlotRenderer = Box) => {
|
|
86234
86292
|
const slotPropsSignal = signal();
|
|
86293
|
+
let filler = null;
|
|
86235
86294
|
const Slot = () => {
|
|
86236
86295
|
const props = slotPropsSignal.value;
|
|
86237
86296
|
return jsx(SlotRenderer, {
|
|
@@ -86240,9 +86299,18 @@ const createSlot = (SlotRenderer = Box) => {
|
|
|
86240
86299
|
});
|
|
86241
86300
|
};
|
|
86242
86301
|
const SlotFill = props => {
|
|
86302
|
+
const fillerRef = useRef();
|
|
86303
|
+
filler = fillerRef;
|
|
86243
86304
|
slotPropsSignal.value = props;
|
|
86244
86305
|
useLayoutEffect(() => {
|
|
86245
86306
|
return () => {
|
|
86307
|
+
// Within one diff preact mounts the newcomer before unmounting the
|
|
86308
|
+
// leaver, so the leaver may no longer be the filler by the time it
|
|
86309
|
+
// is cleaned up.
|
|
86310
|
+
if (filler !== fillerRef) {
|
|
86311
|
+
return;
|
|
86312
|
+
}
|
|
86313
|
+
filler = null;
|
|
86246
86314
|
slotPropsSignal.value = null;
|
|
86247
86315
|
};
|
|
86248
86316
|
}, []);
|