@jsenv/navi 0.29.45 → 0.29.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/jsenv_navi.js +364 -141
- package/dist/jsenv_navi.js.map +32 -21
- package/dist/jsenv_navi_side_effects.js +26 -3
- package/dist/jsenv_navi_side_effects.js.map +2 -2
- package/docs/AI_INSTRUCTIONS.md +9 -0
- package/docs/actions.md +22 -0
- package/docs/control_value.md +6 -0
- package/docs/create_and_edit.md +468 -0
- package/docs/css_architecture.md +52 -0
- package/docs/form_changed.md +2 -0
- package/docs/navigation.md +15 -0
- package/docs/scroll.md +14 -5
- package/docs/z_index.md +21 -8
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* AI reading this file: read ../docs/AI_INSTRUCTIONS.md for context on
|
|
3
3
|
* using @jsenv/navi as intended.
|
|
4
4
|
*/
|
|
5
|
-
import { installImportMetaCssBuild, windowHeightSignal, windowWidthSignal, visualViewportHeightSignal, visualViewportWidthSignal, getAppHeight, getAppWidth,
|
|
5
|
+
import { installImportMetaCssBuild, windowHeightSignal, windowWidthSignal, visualViewportHeightSignal, visualViewportWidthSignal, getAppHeight, getAppWidth, smallTouchScreenSignal } from "./jsenv_navi_side_effects.js";
|
|
6
|
+
export { coarsePointerSignal } from "./jsenv_navi_side_effects.js";
|
|
6
7
|
import { elementIsFocusable, createPubSub, dispatchInternalCustomEvent, dispatchCustomEvent, getElementSignature, findEvent, createValueEffect, getVisuallyVisibleInfo, getFirstVisuallyVisibleAncestor, findFocusDelegateTarget, findFocusable, allowWheelThrough, dispatchPublicCustomEvent, resolveCSSColor, ELEMENT_SIZE_CHANGE, findSelfOrAncestorFixedPosition, visibleRectEffect, pickPositionRelativeTo, getBorderSizes, getPaddingSizes, applyNewPosition, measureLongestVisualLineWidth, chainEvent, waitForPressHeld, suppressClickAfterGesture, startDragToTravel, markDragSource, startDragTo, createIterableWeakSet, createEventGroupLogger, getKeyboardEventDefaultAction, activeElementSignal, normalizeStyle, mergeOneStyle, getPositionedParent, mergeTwoStyles, normalizeStyles, resolveCSSSize, hasCSSSizeUnit, resolveOklchLightness, contrastColor, closestOpenableAncestor, isAncestorOpen, observeAncestorOpenState, getAncestorOpenType, parsePositionArea, snapToPixel, trapFocusInside, trapScrollInside, onAncestorReopen, createGroupTransitionController, getBorderRadius, preventIntermediateScrollbar, createOpacityTransition, watchWheelTravel, scrollRoomTowards, findBefore, findAfter, initFocusGroup, scrollIntoViewScoped, getScrollContainer, canScroll, measureWidestChildRow, performTabNavigation, wheelGestureIsTakenFrom, releaseWheelGesture, claimWheelGesture, dragAfterIntent, stickyAsRelativeCoords, createDragToMoveGestureController, getDropTargetInfo, setStyles, useActiveElement, stringifyStyle as stringifyStyle$1 } from "@jsenv/dom";
|
|
7
8
|
export { contrastColor, findEvent, startDragTo } from "@jsenv/dom";
|
|
8
9
|
import { signal, computed, effect, batch, useSignal } from "@preact/signals";
|
|
@@ -49,17 +50,28 @@ const css$10 = /* css */`
|
|
|
49
50
|
--navi-z-index-control-focused: 2;
|
|
50
51
|
|
|
51
52
|
/* Kept stuck while something scrolls under it: a list header, the head
|
|
52
|
-
and foot of a side panel, a table's sticky cells
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
sticky part
|
|
61
|
-
it
|
|
62
|
-
|
|
53
|
+
and foot of a side panel, a table's sticky cells, the header and
|
|
54
|
+
footer of any scrolling Box. Above raised controls — a control
|
|
55
|
+
scrolling past must go under the header that pins the column it
|
|
56
|
+
belongs to, never over it.
|
|
57
|
+
|
|
58
|
+
A sticky element is a positioned one, so it already wins against
|
|
59
|
+
everything in the flow — the band is what it takes to also win against
|
|
60
|
+
what the page positioned itself, which loses to DOM order otherwise
|
|
61
|
+
(a sticky part is written before what scrolls under it). Box applies
|
|
62
|
+
it by default, isolated, and lets a call site write auto back:
|
|
63
|
+
--box-header-z-index / --box-footer-z-index.
|
|
64
|
+
|
|
65
|
+
"While stuck" is the condition the name states, and it costs something
|
|
66
|
+
to ignore: a sticky part at rest is a block in the flow with nothing
|
|
67
|
+
passing under it, and the band there is what slices whatever a
|
|
68
|
+
neighbouring row lets out of its box. CSS cannot express the
|
|
69
|
+
condition — an element cannot read its own stuck state — so it takes
|
|
70
|
+
measuring, which List does (it marks its parts with a navi-stuck
|
|
71
|
+
attribute against its own scroller and applies the band only there,
|
|
72
|
+
see --list-*-z-index in list.jsx) and Box does not: a generic
|
|
73
|
+
scrolling area does not know what it was given to scroll, and dropping
|
|
74
|
+
to auto there loses to a single position: relative. */
|
|
63
75
|
--navi-z-index-sticky: 10;
|
|
64
76
|
|
|
65
77
|
/* Pinned to the viewport, over the whole page: FixedBar. A decade of its
|
|
@@ -19030,14 +19042,24 @@ import.meta.css = [/* css */`
|
|
|
19030
19042
|
|
|
19031
19043
|
[data-scrollable] {
|
|
19032
19044
|
overflow: var(--x-scrollable-overflow, auto);
|
|
19045
|
+
--box-header-z-index: var(--navi-z-index-sticky);
|
|
19046
|
+
--box-footer-z-index: var(--navi-z-index-sticky);
|
|
19047
|
+
/* The band stays inside this box: without a stacking context here, "in
|
|
19048
|
+
front of my body" would be read as "in front of everything on the page"
|
|
19049
|
+
and a header would reach past a bar or a popup — which is exactly what
|
|
19050
|
+
the decades in navi_z_indexes.js are there to prevent. See
|
|
19051
|
+
docs/z_index.md. */
|
|
19052
|
+
isolation: isolate;
|
|
19033
19053
|
|
|
19034
19054
|
&[data-scrollable-overflow="scroll"] {
|
|
19035
19055
|
--x-scrollable-overflow: scroll;
|
|
19036
19056
|
}
|
|
19037
19057
|
|
|
19038
|
-
/* box-shadow
|
|
19039
|
-
|
|
19040
|
-
|
|
19058
|
+
/* A real border and not a box-shadow: a shadow is drawn outside the box, so
|
|
19059
|
+
it lands on top of whatever comes next in the painting order and loses to
|
|
19060
|
+
it — a body painting its own background over the line that was meant to
|
|
19061
|
+
separate them. The border belongs to the part itself and is always
|
|
19062
|
+
visible; the pixel it adds shifts nothing, these parts never shrink. */
|
|
19041
19063
|
/* The corners are the container's, not the part's: a header sitting at the
|
|
19042
19064
|
top of a rounded box has to follow that curve or it paints square over
|
|
19043
19065
|
it (a dark header in a rounded popup is where this shows). inherit and
|
|
@@ -19045,18 +19067,18 @@ import.meta.css = [/* css */`
|
|
|
19045
19067
|
> [data-header] {
|
|
19046
19068
|
position: sticky;
|
|
19047
19069
|
top: 0;
|
|
19048
|
-
z-index:
|
|
19070
|
+
z-index: var(--box-header-z-index);
|
|
19071
|
+
border-bottom: 1px solid var(--navi-separator-color-default);
|
|
19049
19072
|
border-top-left-radius: inherit;
|
|
19050
19073
|
border-top-right-radius: inherit;
|
|
19051
|
-
box-shadow: 0 1px 0 var(--navi-separator-color-default);
|
|
19052
19074
|
}
|
|
19053
19075
|
> [data-footer] {
|
|
19054
19076
|
position: sticky;
|
|
19055
19077
|
bottom: 0;
|
|
19056
|
-
z-index:
|
|
19078
|
+
z-index: var(--box-footer-z-index);
|
|
19079
|
+
border-top: 1px solid var(--navi-separator-color-default);
|
|
19057
19080
|
border-bottom-right-radius: inherit;
|
|
19058
19081
|
border-bottom-left-radius: inherit;
|
|
19059
|
-
box-shadow: 0 -1px 0 var(--navi-separator-color-default);
|
|
19060
19082
|
}
|
|
19061
19083
|
|
|
19062
19084
|
&:has(> [data-body]) {
|
|
@@ -19070,8 +19092,11 @@ import.meta.css = [/* css */`
|
|
|
19070
19092
|
|
|
19071
19093
|
> [data-header],
|
|
19072
19094
|
> [data-footer] {
|
|
19095
|
+
/* Nothing scrolls under them here — the body does that, next to them —
|
|
19096
|
+
so they are back to being blocks in the flow, and stacking is not
|
|
19097
|
+
their business anymore. */
|
|
19073
19098
|
position: static;
|
|
19074
|
-
z-index:
|
|
19099
|
+
z-index: auto;
|
|
19075
19100
|
flex-shrink: 0;
|
|
19076
19101
|
}
|
|
19077
19102
|
|
|
@@ -25441,6 +25466,13 @@ const useControlProps = (props, {
|
|
|
25441
25466
|
const onButtonInteractionAllowed = e => {
|
|
25442
25467
|
triggerUIAction(e);
|
|
25443
25468
|
const control = ref.current;
|
|
25469
|
+
if (!control) {
|
|
25470
|
+
// What the button just did took the button away: a command that
|
|
25471
|
+
// navigates, a popup closing over it. There is no control left to
|
|
25472
|
+
// ask for an action, and nothing is lost by not asking — what the
|
|
25473
|
+
// press was for has already happened.
|
|
25474
|
+
return;
|
|
25475
|
+
}
|
|
25444
25476
|
tryActionAfterInteractionAllowed(control, {
|
|
25445
25477
|
event: e,
|
|
25446
25478
|
action: boundAction,
|
|
@@ -26989,37 +27021,45 @@ installImportMetaCssBuild(import.meta);const css$W = /* css */`
|
|
|
26989
27021
|
--x-button-border-color: var(--callout-color);
|
|
26990
27022
|
}
|
|
26991
27023
|
|
|
27024
|
+
/* A variant states what the caller did NOT: the frameless ones below move
|
|
27025
|
+
the DEFAULTS (--button-*) and never the resolved values (--x-button-*),
|
|
27026
|
+
so a backgroundColor/background/borderColor prop — which lands inline on
|
|
27027
|
+
this same element — still wins. Two things come with that: the
|
|
27028
|
+
transparent default is written as a fallback of --button-background, so
|
|
27029
|
+
the background prop feeds --button-background-color through it; and the
|
|
27030
|
+
per-state defaults are re-pointed at the base one, otherwise the @layer
|
|
27031
|
+
formulas (hover = 5% black over the background, readonly = the same)
|
|
27032
|
+
would repaint a box the variant just took away. */
|
|
27033
|
+
|
|
26992
27034
|
/* discrete: background on hover, and nothing else — no box at rest, and no
|
|
26993
27035
|
shrink when pressed. What is drawn IS the content (a chevron, a number,
|
|
26994
27036
|
a word), and shrinking it under the finger reads as the content itself
|
|
26995
27037
|
flinching rather than as a button being pressed. */
|
|
26996
27038
|
&[data-variant="discrete"] {
|
|
26997
27039
|
--button-border-width: 0;
|
|
26998
|
-
--
|
|
26999
|
-
--
|
|
27040
|
+
--button-border-color: transparent;
|
|
27041
|
+
--button-border-color-hover: var(--button-border-color);
|
|
27042
|
+
--button-border-color-current: var(--button-border-color);
|
|
27043
|
+
--button-border-color-readonly: var(--button-border-color);
|
|
27044
|
+
--button-border-color-disabled: var(--button-border-color);
|
|
27045
|
+
--button-background-color: var(--button-background, transparent);
|
|
27046
|
+
/* The hover wash is mixed INTO the background instead of replacing it:
|
|
27047
|
+
over the transparent default it is exactly the 8% of currentColor it
|
|
27048
|
+
has always been, and over a backgroundColor the caller gave it darkens
|
|
27049
|
+
that color rather than erasing it. */
|
|
27050
|
+
--button-background-color-hover: color-mix(
|
|
27051
|
+
in srgb,
|
|
27052
|
+
currentColor 8%,
|
|
27053
|
+
var(--button-background-color)
|
|
27054
|
+
);
|
|
27055
|
+
--button-background-color-readonly: var(--button-background-color);
|
|
27056
|
+
--button-background-color-disabled: var(--button-background-color);
|
|
27000
27057
|
|
|
27001
27058
|
&[data-pressed] {
|
|
27002
27059
|
.navi_button_content {
|
|
27003
27060
|
transform: none;
|
|
27004
27061
|
}
|
|
27005
27062
|
}
|
|
27006
|
-
|
|
27007
|
-
&[data-hover] {
|
|
27008
|
-
--x-button-border-color: transparent;
|
|
27009
|
-
--x-button-background-color: color-mix(
|
|
27010
|
-
in srgb,
|
|
27011
|
-
currentColor 8%,
|
|
27012
|
-
transparent
|
|
27013
|
-
);
|
|
27014
|
-
}
|
|
27015
|
-
&[data-readonly] {
|
|
27016
|
-
--x-button-border-color: transparent;
|
|
27017
|
-
--x-button-background-color: transparent;
|
|
27018
|
-
}
|
|
27019
|
-
&[data-disabled] {
|
|
27020
|
-
--x-button-border-color: transparent;
|
|
27021
|
-
--x-button-background-color: transparent;
|
|
27022
|
-
}
|
|
27023
27063
|
}
|
|
27024
27064
|
/* bare: discrete, minus the background on hover. For a control whose own
|
|
27025
27065
|
drawing IS the button (a carousel bullet, a swatch), where a box lighting
|
|
@@ -27028,13 +27068,16 @@ installImportMetaCssBuild(import.meta);const css$W = /* css */`
|
|
|
27028
27068
|
on focus, commandable. */
|
|
27029
27069
|
&[data-variant="bare"] {
|
|
27030
27070
|
--button-border-width: 0;
|
|
27031
|
-
--
|
|
27032
|
-
--
|
|
27071
|
+
--button-border-color: transparent;
|
|
27072
|
+
--button-border-color-hover: var(--button-border-color);
|
|
27073
|
+
--button-border-color-current: var(--button-border-color);
|
|
27074
|
+
--button-border-color-readonly: var(--button-border-color);
|
|
27075
|
+
--button-border-color-disabled: var(--button-border-color);
|
|
27076
|
+
--button-background-color: var(--button-background, transparent);
|
|
27077
|
+
--button-background-color-hover: var(--button-background-color);
|
|
27078
|
+
--button-background-color-readonly: var(--button-background-color);
|
|
27079
|
+
--button-background-color-disabled: var(--button-background-color);
|
|
27033
27080
|
|
|
27034
|
-
&[data-hover] {
|
|
27035
|
-
--x-button-background-color: transparent;
|
|
27036
|
-
--x-button-border-color: transparent;
|
|
27037
|
-
}
|
|
27038
27081
|
&[data-pressed] {
|
|
27039
27082
|
.navi_button_content {
|
|
27040
27083
|
transform: none;
|
|
@@ -27043,36 +27086,34 @@ installImportMetaCssBuild(import.meta);const css$W = /* css */`
|
|
|
27043
27086
|
}
|
|
27044
27087
|
/* discrete-border: border on hover */
|
|
27045
27088
|
&[data-variant="discrete-border"] {
|
|
27046
|
-
--
|
|
27089
|
+
--button-background-color: var(--button-background, transparent);
|
|
27090
|
+
--button-background-color-hover: var(--button-background-color);
|
|
27091
|
+
--button-background-color-readonly: var(--button-background-color);
|
|
27092
|
+
--button-background-color-disabled: var(--button-background-color);
|
|
27093
|
+
/* The border is the whole point of this variant: it is absent at rest
|
|
27094
|
+
and drawn on hover, so only the resting color goes transparent — the
|
|
27095
|
+
hover one keeps the @layer formula, now mixed from whatever
|
|
27096
|
+
borderColor the caller gave. */
|
|
27047
27097
|
--x-button-border-color: transparent;
|
|
27048
27098
|
|
|
27049
27099
|
&[data-hover] {
|
|
27050
27100
|
--x-button-border-color: var(--button-border-color-hover);
|
|
27051
27101
|
}
|
|
27052
|
-
&[data-readonly]
|
|
27053
|
-
--x-button-border-color: transparent;
|
|
27054
|
-
}
|
|
27102
|
+
&[data-readonly],
|
|
27055
27103
|
&[data-disabled] {
|
|
27056
27104
|
--x-button-border-color: transparent;
|
|
27057
27105
|
}
|
|
27058
27106
|
}
|
|
27059
27107
|
/* border variant: no background, border only */
|
|
27060
27108
|
&[data-variant="border"] {
|
|
27061
|
-
--
|
|
27062
|
-
|
|
27063
|
-
|
|
27064
|
-
|
|
27065
|
-
|
|
27066
|
-
|
|
27067
|
-
|
|
27068
|
-
|
|
27069
|
-
}
|
|
27070
|
-
&[data-readonly] {
|
|
27071
|
-
--x-button-background-color: transparent;
|
|
27072
|
-
}
|
|
27073
|
-
&[data-disabled] {
|
|
27074
|
-
--x-button-background-color: transparent;
|
|
27075
|
-
}
|
|
27109
|
+
--button-background-color: var(--button-background, transparent);
|
|
27110
|
+
--button-background-color-hover: color-mix(
|
|
27111
|
+
in srgb,
|
|
27112
|
+
currentColor 8%,
|
|
27113
|
+
var(--button-background-color)
|
|
27114
|
+
);
|
|
27115
|
+
--button-background-color-readonly: var(--button-background-color);
|
|
27116
|
+
--button-background-color-disabled: var(--button-background-color);
|
|
27076
27117
|
}
|
|
27077
27118
|
/* Last word on the shrink, over whatever the variant decided: the variant
|
|
27078
27119
|
guesses from how the button is drawn, and that guess is wrong as soon as
|
|
@@ -29169,17 +29210,19 @@ const css$V = /* css */`
|
|
|
29169
29210
|
* shown via the non-modal `.show()` instead, staying in normal document
|
|
29170
29211
|
* flow inside its own positioned ancestor — confined to (and clipped by)
|
|
29171
29212
|
* that container instead of the whole viewport.
|
|
29172
|
-
* @param {boolean} [props.
|
|
29173
|
-
* (docked flush to the bottom edge, full width)
|
|
29174
|
-
* and leaves it alone otherwise. For a dialog meant to be interacted
|
|
29175
|
-
* rather than merely read:
|
|
29176
|
-
* the screen and a centered box ends up both cramped and out of thumb
|
|
29177
|
-
*
|
|
29178
|
-
*
|
|
29179
|
-
*
|
|
29180
|
-
*
|
|
29181
|
-
*
|
|
29182
|
-
*
|
|
29213
|
+
* @param {boolean} [props.dockedOnSmallTouchScreen] - Turns the dialog into a
|
|
29214
|
+
* bottom sheet (docked flush to the bottom edge, full width) on a small touch
|
|
29215
|
+
* screen, and leaves it alone otherwise. For a dialog meant to be interacted
|
|
29216
|
+
* with rather than merely read: on a phone the keyboard owns the bottom of
|
|
29217
|
+
* the screen and a centered box ends up both cramped and out of thumb reach,
|
|
29218
|
+
* while under a mouse the centered box is already the right shape. Both
|
|
29219
|
+
* halves of the name matter (`smallTouchScreenSignal`): touch alone would
|
|
29220
|
+
* dock a big touch screen — a tablet, a kiosk panel — a whole screen away
|
|
29221
|
+
* from where the finger just tapped, and size alone would dock a narrow
|
|
29222
|
+
* desktop window, which is still a mouse. It supplies defaults for
|
|
29223
|
+
* `positionArea`, `marginWithContainer`, `expandX` and `scrollCapture`, so
|
|
29224
|
+
* any of them can still be pinned explicitly. Re-resolves live as the pointer
|
|
29225
|
+
* type or the window size changes.
|
|
29183
29226
|
* @param {string} [props.positionArea="center"] - Where to dock the dialog
|
|
29184
29227
|
* within its container (the viewport for `layer="top"`, the positioned
|
|
29185
29228
|
* ancestor for `layer="local"`) — Dialog is never anchored to a real
|
|
@@ -29192,8 +29235,8 @@ const css$V = /* css */`
|
|
|
29192
29235
|
* `inset(top)`) for the overlapping variant.
|
|
29193
29236
|
* @param {boolean} [props.expand] - Shorthand for both `expandX` and `expandY`.
|
|
29194
29237
|
* @param {boolean} [props.expandX] - Stretches the dialog to the full width its
|
|
29195
|
-
* container allows (`--dialog-maxmax-width`). Set by
|
|
29196
|
-
* touch
|
|
29238
|
+
* container allows (`--dialog-maxmax-width`). Set by
|
|
29239
|
+
* `dockedOnSmallTouchScreen` on a small touch screen.
|
|
29197
29240
|
* @param {boolean} [props.expandY] - Same, vertically
|
|
29198
29241
|
* (`--dialog-maxmax-height`).
|
|
29199
29242
|
* @param {string|number} [props.marginWithContainer="3appw"] - Minimum gap kept
|
|
@@ -29223,7 +29266,7 @@ const css$V = /* css */`
|
|
|
29223
29266
|
* A `layer="local"` dialog always locks its own positioned ancestor's
|
|
29224
29267
|
* scroll while open (its backdrop only covers the scrollport, so scrolling
|
|
29225
29268
|
* there would reveal uncovered content); this prop extends the lock to the
|
|
29226
|
-
* whole page. Defaults to `true` for a dialog docked by `
|
|
29269
|
+
* whole page. Defaults to `true` for a dialog docked by `dockedOnSmallTouchScreen`.
|
|
29227
29270
|
* @param {boolean|"auto"|"fading"|"scaling"|"sliding"|`slide-from-${string}`} [props.animation]
|
|
29228
29271
|
* - `true`/`"auto"` resolves to `"scaling"` for a centered `positionArea`,
|
|
29229
29272
|
* or a concrete `"slide-from-*"` direction otherwise. Any other explicit
|
|
@@ -29406,10 +29449,10 @@ const DialogLocal = props => {
|
|
|
29406
29449
|
* contentProps]` — `backdropProps` is `null` for the via-attribute renderer
|
|
29407
29450
|
* (its own backdrop is native, not a real element).
|
|
29408
29451
|
*/
|
|
29409
|
-
// What a dialog turns into
|
|
29410
|
-
// the dialog in the zone a
|
|
29411
|
-
//
|
|
29412
|
-
//
|
|
29452
|
+
// What a dialog turns into on a small touch screen. "bottom" is not a taste:
|
|
29453
|
+
// it puts the dialog in the zone a phone is actually operated from — where the
|
|
29454
|
+
// thumbs rest and where the virtual keyboard comes up — instead of the middle
|
|
29455
|
+
// of the screen, which is the farthest point from both.
|
|
29413
29456
|
// Only defaults: an explicitly passed prop still wins, so the docked shape can
|
|
29414
29457
|
// be adjusted one axis at a time instead of being all-or-nothing.
|
|
29415
29458
|
const DOCKED = {
|
|
@@ -29447,7 +29490,7 @@ const useDialogProps = props => {
|
|
|
29447
29490
|
// .show() instead, staying in normal document flow, position: absolute
|
|
29448
29491
|
// relative to its own positioned ancestor. See this file's top comment.
|
|
29449
29492
|
layer = "top",
|
|
29450
|
-
|
|
29493
|
+
dockedOnSmallTouchScreen,
|
|
29451
29494
|
// Same grammar as Popover's own positionArea — see this file's top
|
|
29452
29495
|
// comment and popup_shared.js's parsePositionArea.
|
|
29453
29496
|
positionArea: positionAreaProp,
|
|
@@ -29500,9 +29543,10 @@ const useDialogProps = props => {
|
|
|
29500
29543
|
});
|
|
29501
29544
|
const isModal = layer === "top";
|
|
29502
29545
|
const ref = props.ref;
|
|
29503
|
-
// Only touch changes anything:
|
|
29504
|
-
//
|
|
29505
|
-
|
|
29546
|
+
// Only a small touch screen changes anything: on a mouse — and on a touch
|
|
29547
|
+
// screen too big to reach the bottom edge of — a dialog already wants to be
|
|
29548
|
+
// the centered box it is by default, so there is nothing to resolve.
|
|
29549
|
+
const isDocked = dockedOnSmallTouchScreen && smallTouchScreenSignal.value;
|
|
29506
29550
|
const positionArea = positionAreaProp ?? (isDocked ? DOCKED.positionArea : "center");
|
|
29507
29551
|
const marginWithContainer = marginWithContainerProp ?? (isDocked ? DOCKED.marginWithContainer :
|
|
29508
29552
|
// A share of whatever holds the dialog: the app's own screen for a
|
|
@@ -31645,8 +31689,8 @@ const css$T = /* css */`
|
|
|
31645
31689
|
* @property {"close"|"cancel"|"capture"|"none"} [pointerInteractionOutsideEffect]
|
|
31646
31690
|
* - What a click outside does. `"capture"`/`"none"` force an explicit answer
|
|
31647
31691
|
* by refusing to treat a click elsewhere as one.
|
|
31648
|
-
* @property {boolean} [
|
|
31649
|
-
* into a bottom sheet
|
|
31692
|
+
* @property {boolean} [dockedOnSmallTouchScreen] - `"dialog"` mode only: turn
|
|
31693
|
+
* the popup into a bottom sheet on a small touch screen.
|
|
31650
31694
|
* @property {(params: { message: import("ignore:preact").ComponentChildren }) => import("ignore:preact").ComponentChildren} [renderContent]
|
|
31651
31695
|
* - Replaces the popup body — the question and the two buttons — for every
|
|
31652
31696
|
* confirmation at once. The per-button `confirmPopupContent` prop is the same
|
|
@@ -31664,7 +31708,7 @@ const confirmPopupOptions = {
|
|
|
31664
31708
|
animationDuration: undefined,
|
|
31665
31709
|
positionArea: undefined,
|
|
31666
31710
|
pointerInteractionOutsideEffect: "close",
|
|
31667
|
-
|
|
31711
|
+
dockedOnSmallTouchScreen: false,
|
|
31668
31712
|
renderContent: undefined
|
|
31669
31713
|
};
|
|
31670
31714
|
|
|
@@ -31746,7 +31790,7 @@ const ConfirmPopup = ({
|
|
|
31746
31790
|
animationDuration,
|
|
31747
31791
|
positionArea,
|
|
31748
31792
|
pointerInteractionOutsideEffect,
|
|
31749
|
-
|
|
31793
|
+
dockedOnSmallTouchScreen,
|
|
31750
31794
|
renderContent
|
|
31751
31795
|
} = confirmPopupOptions;
|
|
31752
31796
|
|
|
@@ -31782,7 +31826,7 @@ const ConfirmPopup = ({
|
|
|
31782
31826
|
if (mode === "dialog") {
|
|
31783
31827
|
return jsx(Dialog, {
|
|
31784
31828
|
className: "navi_confirm_popup",
|
|
31785
|
-
|
|
31829
|
+
dockedOnSmallTouchScreen: dockedOnSmallTouchScreen,
|
|
31786
31830
|
...popupProps,
|
|
31787
31831
|
children: body
|
|
31788
31832
|
});
|
|
@@ -32037,6 +32081,16 @@ const debounceSignal = (
|
|
|
32037
32081
|
* The action will not fire while the user is actively changing filters; it fires once
|
|
32038
32082
|
* they pause for half a second.
|
|
32039
32083
|
*/
|
|
32084
|
+
// The run is not awaited here, and a rejection nobody waits for is an unhandled
|
|
32085
|
+
// one — in dev, an error overlay thrown over a page that is already saying what
|
|
32086
|
+
// went wrong. Nothing is lost by dropping it: the failure is held by the action
|
|
32087
|
+
// itself, and whoever reads it (useAsyncData, <Button action>) is what shows it.
|
|
32088
|
+
const runUnwatched = (result) => {
|
|
32089
|
+
if (result && typeof result.catch === "function") {
|
|
32090
|
+
result.catch(() => {});
|
|
32091
|
+
}
|
|
32092
|
+
};
|
|
32093
|
+
|
|
32040
32094
|
const actionRunEffect = (
|
|
32041
32095
|
action,
|
|
32042
32096
|
deriveActionParamsFromSignals,
|
|
@@ -32086,7 +32140,7 @@ const actionRunEffect = (
|
|
|
32086
32140
|
// falsy params, don't run
|
|
32087
32141
|
return;
|
|
32088
32142
|
}
|
|
32089
|
-
actionTarget.run({ reason: "truthy params first run" });
|
|
32143
|
+
runUnwatched(actionTarget.run({ reason: "truthy params first run" }));
|
|
32090
32144
|
return;
|
|
32091
32145
|
}
|
|
32092
32146
|
|
|
@@ -32103,16 +32157,20 @@ const actionRunEffect = (
|
|
|
32103
32157
|
}
|
|
32104
32158
|
if (!actionTargetPrevious.params) {
|
|
32105
32159
|
// coming from falsy-params state: action may already be cached, avoid unnecessary rerun
|
|
32106
|
-
|
|
32160
|
+
runUnwatched(
|
|
32161
|
+
actionTarget.run({ reason: "params restored from falsy state" }),
|
|
32162
|
+
);
|
|
32107
32163
|
} else {
|
|
32108
|
-
actionTarget.rerun({ reason: "params modified" });
|
|
32164
|
+
runUnwatched(actionTarget.rerun({ reason: "params modified" }));
|
|
32109
32165
|
}
|
|
32110
32166
|
}
|
|
32111
32167
|
},
|
|
32112
32168
|
...options,
|
|
32113
32169
|
});
|
|
32114
32170
|
if (actionParamsSignal.peek()) {
|
|
32115
|
-
|
|
32171
|
+
runUnwatched(
|
|
32172
|
+
actionRunnedByThisEffect.run({ reason: "initial truthy params" }),
|
|
32173
|
+
);
|
|
32116
32174
|
}
|
|
32117
32175
|
return actionRunnedByThisEffect;
|
|
32118
32176
|
};
|
|
@@ -35236,6 +35294,24 @@ const TYPE_CONVERTERS = {
|
|
|
35236
35294
|
},
|
|
35237
35295
|
};
|
|
35238
35296
|
|
|
35297
|
+
/**
|
|
35298
|
+
* A container has put its page on screen — or as much of it as it can.
|
|
35299
|
+
*
|
|
35300
|
+
* A route matching is a signal changing, and the page it selects reaches the
|
|
35301
|
+
* DOM only once Preact has rendered — an unknown number of passes later, in an
|
|
35302
|
+
* unknown number of microtasks. Anyone who needs the page as it IS rather than
|
|
35303
|
+
* as it has been decided (a travel about to have its picture taken by the
|
|
35304
|
+
* browser, see route_travel.jsx) waits for this instead of counting.
|
|
35305
|
+
*
|
|
35306
|
+
* A page waiting on data is announced too, by the boundary showing its loading
|
|
35307
|
+
* state (see Loading in use_async_data.jsx): what the container could put on
|
|
35308
|
+
* screen is what the browser is about to take a picture of, and a page that
|
|
35309
|
+
* cannot render yet would otherwise be waited on until the transition dies of
|
|
35310
|
+
* it. It lives in a module of its own for that: the async layer says it as much
|
|
35311
|
+
* as the router does, and neither can import the other.
|
|
35312
|
+
*/
|
|
35313
|
+
const [publishRouteRender, observeRouteRender] = createPubSub();
|
|
35314
|
+
|
|
35239
35315
|
const promiseStateWeakMap = new WeakMap();
|
|
35240
35316
|
const usePromiseAsyncData = (
|
|
35241
35317
|
promise,
|
|
@@ -35290,7 +35366,8 @@ const useForceRender = () => {
|
|
|
35290
35366
|
|
|
35291
35367
|
const useAsyncData = (promiseOrAction, {
|
|
35292
35368
|
loading = "delegate",
|
|
35293
|
-
error = "delegate"
|
|
35369
|
+
error = "delegate",
|
|
35370
|
+
onLoad
|
|
35294
35371
|
} = {}) => {
|
|
35295
35372
|
const isAction = Boolean(promiseOrAction && promiseOrAction.isAction);
|
|
35296
35373
|
if (loading === true) {
|
|
@@ -35302,7 +35379,8 @@ const useAsyncData = (promiseOrAction, {
|
|
|
35302
35379
|
if (isAction) {
|
|
35303
35380
|
return useActionAsyncData(promiseOrAction, {
|
|
35304
35381
|
loadingEffect: loading,
|
|
35305
|
-
errorEffect: error
|
|
35382
|
+
errorEffect: error,
|
|
35383
|
+
onLoad
|
|
35306
35384
|
});
|
|
35307
35385
|
}
|
|
35308
35386
|
return usePromiseAsyncData(promiseOrAction, {
|
|
@@ -35319,12 +35397,14 @@ const dismissedActionWeakSet = new WeakSet();
|
|
|
35319
35397
|
const dismissedActionPendingPromiseWeakMap = new WeakMap();
|
|
35320
35398
|
const useActionAsyncData = (action, {
|
|
35321
35399
|
loadingEffect,
|
|
35322
|
-
errorEffect
|
|
35400
|
+
errorEffect,
|
|
35401
|
+
onLoad
|
|
35323
35402
|
}) => {
|
|
35324
35403
|
const loadingRef = useContext(LoadingContext);
|
|
35325
35404
|
if (!loadingRef) {
|
|
35326
35405
|
throw new Error("Missing <Loading>");
|
|
35327
35406
|
}
|
|
35407
|
+
useOnLoad(action, onLoad);
|
|
35328
35408
|
|
|
35329
35409
|
// Use peek() instead of .value to avoid subscribing this component to the signal.
|
|
35330
35410
|
// Reading .value would make Preact re-render the component reactively when the state
|
|
@@ -35445,6 +35525,41 @@ const useActionAsyncData = (action, {
|
|
|
35445
35525
|
throw pendingPromise;
|
|
35446
35526
|
};
|
|
35447
35527
|
|
|
35528
|
+
// What a screen does with the data once, when it becomes known (see onLoad in
|
|
35529
|
+
// the JSDoc above). Kept apart because the two questions it answers are not the
|
|
35530
|
+
// ones the hook around it answers: WHEN — a layout effect, so a form taking its
|
|
35531
|
+
// reference in the same tick sees what was written; and HOW OFTEN — once per set
|
|
35532
|
+
// of params, which is the action's own answer to "is this another thing or the
|
|
35533
|
+
// same one again".
|
|
35534
|
+
const NOTHING_SEEDED = Symbol("nothing_seeded");
|
|
35535
|
+
const useOnLoad = (action, onLoad) => {
|
|
35536
|
+
const onLoadRef = useRef(onLoad);
|
|
35537
|
+
onLoadRef.current = onLoad;
|
|
35538
|
+
const paramsSeededRef = useRef(NOTHING_SEEDED);
|
|
35539
|
+
useLayoutEffect(() => {
|
|
35540
|
+
const callback = onLoadRef.current;
|
|
35541
|
+
if (!callback) {
|
|
35542
|
+
return;
|
|
35543
|
+
}
|
|
35544
|
+
if (action.runningStateSignal.peek() !== COMPLETED) {
|
|
35545
|
+
return;
|
|
35546
|
+
}
|
|
35547
|
+
const data = action.dataSignal.peek();
|
|
35548
|
+
if (data === undefined) {
|
|
35549
|
+
return;
|
|
35550
|
+
}
|
|
35551
|
+
const params = action.paramsSignal.peek();
|
|
35552
|
+
const paramsSeeded = paramsSeededRef.current;
|
|
35553
|
+
if (paramsSeeded !== NOTHING_SEEDED && compareTwoJsValues(params, paramsSeeded)) {
|
|
35554
|
+
return;
|
|
35555
|
+
}
|
|
35556
|
+
paramsSeededRef.current = params;
|
|
35557
|
+
callback(data, {
|
|
35558
|
+
params
|
|
35559
|
+
});
|
|
35560
|
+
});
|
|
35561
|
+
};
|
|
35562
|
+
|
|
35448
35563
|
// ─── Loading ──────────────────────────────────────────────────────────────────
|
|
35449
35564
|
// Wraps Suspense. Provides LoadingContext so useAction can write the suspension
|
|
35450
35565
|
// reason. LoadingFallback reads that reason and subscribes to the action so it
|
|
@@ -35484,6 +35599,14 @@ const LoadingFallback = ({
|
|
|
35484
35599
|
setTick(n => n + 1);
|
|
35485
35600
|
});
|
|
35486
35601
|
}, [action]);
|
|
35602
|
+
// A page that suspends never gets to say it is on screen — its own effects
|
|
35603
|
+
// are held with it — so this says it for it: what the document shows of the
|
|
35604
|
+
// page arriving is this. Anyone waiting for the page to be there before
|
|
35605
|
+
// moving (a travel about to have its picture taken, see route_travel.jsx)
|
|
35606
|
+
// would otherwise wait for a render that cannot happen until the data does.
|
|
35607
|
+
useLayoutEffect(() => {
|
|
35608
|
+
publishRouteRender();
|
|
35609
|
+
});
|
|
35487
35610
|
if (loadingRef.current.reason !== "loading") {
|
|
35488
35611
|
return null;
|
|
35489
35612
|
}
|
|
@@ -36916,7 +37039,6 @@ const Head = ({
|
|
|
36916
37039
|
* ```
|
|
36917
37040
|
*/
|
|
36918
37041
|
|
|
36919
|
-
const [publishRouteRender, observeRouteRender] = createPubSub();
|
|
36920
37042
|
|
|
36921
37043
|
/**
|
|
36922
37044
|
* Keep every container showing the page it is showing, whatever the routes say.
|
|
@@ -37204,6 +37326,10 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
37204
37326
|
const CAN_KEEP_PICTURE = Boolean(document.startViewTransition && !document.startViewTransition.isPolyfill);
|
|
37205
37327
|
const startViewTransition = ensureDocumentStartViewTransition();
|
|
37206
37328
|
const TRAVEL_ATTRIBUTE = "data-navi-route-travel";
|
|
37329
|
+
// Which way the pages move, said on the document: the pictures of a transition
|
|
37330
|
+
// hang off the root, not off the box that travels, so the box's own `axis` has
|
|
37331
|
+
// to be lent to the document for the length of the travel.
|
|
37332
|
+
const TRAVEL_AXIS_ATTRIBUTE = "data-navi-route-travel-axis";
|
|
37207
37333
|
// While a finger holds the travel: the pictures stand still and go exactly
|
|
37208
37334
|
// where it says (see the CSS, and scrubTravel).
|
|
37209
37335
|
const HOLD_ATTRIBUTE = "data-navi-route-travel-held";
|
|
@@ -37397,6 +37523,28 @@ const css$R = /* css */`
|
|
|
37397
37523
|
}
|
|
37398
37524
|
}
|
|
37399
37525
|
|
|
37526
|
+
/* The same four movements, along the axis the pages are laid out on: the
|
|
37527
|
+
start of a column is its top, so going forward there is the page rising and
|
|
37528
|
+
the next one coming up from below. */
|
|
37529
|
+
:root[${TRAVEL_AXIS_ATTRIBUTE}="y"] {
|
|
37530
|
+
&[${TRAVEL_ATTRIBUTE}="forward"] {
|
|
37531
|
+
&::view-transition-old(navi-route-travel) {
|
|
37532
|
+
animation-name: navi-route-travel-leave-towards-top;
|
|
37533
|
+
}
|
|
37534
|
+
&::view-transition-new(navi-route-travel) {
|
|
37535
|
+
animation-name: navi-route-travel-enter-from-bottom;
|
|
37536
|
+
}
|
|
37537
|
+
}
|
|
37538
|
+
&[${TRAVEL_ATTRIBUTE}="back"] {
|
|
37539
|
+
&::view-transition-old(navi-route-travel) {
|
|
37540
|
+
animation-name: navi-route-travel-leave-towards-bottom;
|
|
37541
|
+
}
|
|
37542
|
+
&::view-transition-new(navi-route-travel) {
|
|
37543
|
+
animation-name: navi-route-travel-enter-from-top;
|
|
37544
|
+
}
|
|
37545
|
+
}
|
|
37546
|
+
}
|
|
37547
|
+
|
|
37400
37548
|
@keyframes navi-route-travel-leave-towards-start {
|
|
37401
37549
|
from {
|
|
37402
37550
|
translate: 0 0;
|
|
@@ -37429,6 +37577,38 @@ const css$R = /* css */`
|
|
|
37429
37577
|
translate: 0 0;
|
|
37430
37578
|
}
|
|
37431
37579
|
}
|
|
37580
|
+
@keyframes navi-route-travel-leave-towards-top {
|
|
37581
|
+
from {
|
|
37582
|
+
translate: 0 0;
|
|
37583
|
+
}
|
|
37584
|
+
to {
|
|
37585
|
+
translate: 0 -100%;
|
|
37586
|
+
}
|
|
37587
|
+
}
|
|
37588
|
+
@keyframes navi-route-travel-enter-from-bottom {
|
|
37589
|
+
from {
|
|
37590
|
+
translate: 0 100%;
|
|
37591
|
+
}
|
|
37592
|
+
to {
|
|
37593
|
+
translate: 0 0;
|
|
37594
|
+
}
|
|
37595
|
+
}
|
|
37596
|
+
@keyframes navi-route-travel-leave-towards-bottom {
|
|
37597
|
+
from {
|
|
37598
|
+
translate: 0 0;
|
|
37599
|
+
}
|
|
37600
|
+
to {
|
|
37601
|
+
translate: 0 100%;
|
|
37602
|
+
}
|
|
37603
|
+
}
|
|
37604
|
+
@keyframes navi-route-travel-enter-from-top {
|
|
37605
|
+
from {
|
|
37606
|
+
translate: 0 -100%;
|
|
37607
|
+
}
|
|
37608
|
+
to {
|
|
37609
|
+
translate: 0 0;
|
|
37610
|
+
}
|
|
37611
|
+
}
|
|
37432
37612
|
`;
|
|
37433
37613
|
|
|
37434
37614
|
/**
|
|
@@ -37565,6 +37745,7 @@ const RouteTravel = ({
|
|
|
37565
37745
|
// own for as long as it is the one travelling.
|
|
37566
37746
|
nameForTravel(elementRef.current);
|
|
37567
37747
|
document.documentElement.setAttribute(TRAVEL_ATTRIBUTE, direction);
|
|
37748
|
+
document.documentElement.setAttribute(TRAVEL_AXIS_ATTRIBUTE, axis);
|
|
37568
37749
|
if (scrub) {
|
|
37569
37750
|
holdPictures(travel);
|
|
37570
37751
|
document.documentElement.setAttribute(DRAGGED_ATTRIBUTE, "");
|
|
@@ -37578,14 +37759,21 @@ const RouteTravel = ({
|
|
|
37578
37759
|
const releaseRendering = renderingHeldForRouting || holdRendering();
|
|
37579
37760
|
renderingHeldForRouting = null;
|
|
37580
37761
|
// The picture the browser is about to take must be of the page that was
|
|
37581
|
-
// asked for, and a route matching is not yet a page rendered.
|
|
37762
|
+
// asked for, and a route matching is not yet a page rendered. Watched from
|
|
37763
|
+
// here rather than from inside the callback below: the browser calls that
|
|
37764
|
+
// callback a frame later, and a navigation that has already been decided
|
|
37765
|
+
// (what follows a send, a command) renders its page in between. A wait
|
|
37766
|
+
// armed then waits for something that has already happened — until the
|
|
37767
|
+
// browser gives up on the transition, leaving the page it was leaving on
|
|
37768
|
+
// screen and an error nobody asked for.
|
|
37769
|
+
const renderWait = armRouteRenderWait();
|
|
37582
37770
|
const viewTransition = startViewTransition(async () => {
|
|
37583
37771
|
await whilePageRenders(page, async () => {
|
|
37584
37772
|
releaseRendering();
|
|
37585
37773
|
if (change) {
|
|
37586
37774
|
await change();
|
|
37587
37775
|
}
|
|
37588
|
-
});
|
|
37776
|
+
}, renderWait);
|
|
37589
37777
|
// The page arriving is in the DOM and the transition has not started
|
|
37590
37778
|
// playing: the one moment both boxes can be known.
|
|
37591
37779
|
holdTravelHeight(elementRef.current, heightBefore);
|
|
@@ -37610,6 +37798,7 @@ const RouteTravel = ({
|
|
|
37610
37798
|
viewTransition.finished.catch(() => {
|
|
37611
37799
|
// A transition that fails before it ever calls back leaves the page held:
|
|
37612
37800
|
// whoever asked for the hold gives it back, here as everywhere else.
|
|
37801
|
+
renderWait.stop();
|
|
37613
37802
|
releaseRendering();
|
|
37614
37803
|
endTravel(travel);
|
|
37615
37804
|
});
|
|
@@ -37913,6 +38102,7 @@ const RouteTravel = ({
|
|
|
37913
38102
|
// rather than pick.
|
|
37914
38103
|
unnameAfterTravel(elementRef.current);
|
|
37915
38104
|
document.documentElement.removeAttribute(TRAVEL_ATTRIBUTE);
|
|
38105
|
+
document.documentElement.removeAttribute(TRAVEL_AXIS_ATTRIBUTE);
|
|
37916
38106
|
document.documentElement.removeAttribute(DRAGGED_ATTRIBUTE);
|
|
37917
38107
|
document.documentElement.removeAttribute(TURNED_ATTRIBUTE);
|
|
37918
38108
|
releaseTravelHeight();
|
|
@@ -38475,20 +38665,30 @@ const scrubTravel = (travel, ratio) => {
|
|
|
38475
38665
|
// inside the callback of a view transition: the browser has stopped rendering
|
|
38476
38666
|
// and is waiting on this very promise to take its picture, so a wait that never
|
|
38477
38667
|
// ends is a page frozen under a transition that never became ready.
|
|
38478
|
-
|
|
38668
|
+
// Listening starts before the change, or a render landing while the change is
|
|
38669
|
+
// being awaited is a render nobody heard. Armed apart from the wait itself
|
|
38670
|
+
// because the two do not always happen at the same moment: a view transition
|
|
38671
|
+
// calls its update callback a frame after it is started, and the render can
|
|
38672
|
+
// land in that gap — see beginTravel, which arms this the moment the travel is
|
|
38673
|
+
// decided and hands it over.
|
|
38674
|
+
const armRouteRenderWait = () => {
|
|
38479
38675
|
let stopListening;
|
|
38480
38676
|
const rendered = new Promise(resolve => {
|
|
38481
|
-
// Listened for before the change, or a render landing while the change is
|
|
38482
|
-
// being awaited is a render nobody heard.
|
|
38483
38677
|
stopListening = observeRouteRender(resolve);
|
|
38484
38678
|
});
|
|
38679
|
+
return {
|
|
38680
|
+
rendered,
|
|
38681
|
+
stop: () => stopListening()
|
|
38682
|
+
};
|
|
38683
|
+
};
|
|
38684
|
+
const whilePageRenders = async (page, change, wait = armRouteRenderWait()) => {
|
|
38485
38685
|
try {
|
|
38486
38686
|
await change();
|
|
38487
38687
|
if (pageIsCurrent(page)) {
|
|
38488
|
-
await rendered;
|
|
38688
|
+
await wait.rendered;
|
|
38489
38689
|
}
|
|
38490
38690
|
} finally {
|
|
38491
|
-
|
|
38691
|
+
wait.stop();
|
|
38492
38692
|
}
|
|
38493
38693
|
};
|
|
38494
38694
|
|
|
@@ -38536,12 +38736,20 @@ const pageIsCurrent = ({
|
|
|
38536
38736
|
}
|
|
38537
38737
|
return params ? route.matchesParams(params) : true;
|
|
38538
38738
|
};
|
|
38539
|
-
//
|
|
38540
|
-
//
|
|
38739
|
+
// The FIRST page that answers, as with the branches of a <Route>: several
|
|
38740
|
+
// routes match at once — a literal one and the parameterized one it is a case of
|
|
38741
|
+
// ("/games/new" is also a "/games/:gameId"), a section and the page inside it —
|
|
38742
|
+
// and the row has to be on the page the router is showing, which is the first
|
|
38743
|
+
// one written that matches.
|
|
38744
|
+
//
|
|
38745
|
+
// Every page is read all the same, never only up to the one that answers yes: a
|
|
38746
|
+
// page that is not the current one today is the one that must wake the reader
|
|
38747
|
+
// tomorrow.
|
|
38541
38748
|
const currentPageIndex = pages => {
|
|
38542
38749
|
let currentIndex = -1;
|
|
38543
38750
|
for (let i = 0; i < pages.length; i++) {
|
|
38544
|
-
|
|
38751
|
+
const isCurrent = pageIsCurrent(pages[i]);
|
|
38752
|
+
if (isCurrent && currentIndex === -1) {
|
|
38545
38753
|
currentIndex = i;
|
|
38546
38754
|
}
|
|
38547
38755
|
}
|
|
@@ -52361,7 +52569,7 @@ const PickerContentInsidePopup = props => {
|
|
|
52361
52569
|
// above: those exist because "expand" already means something on the picker
|
|
52362
52570
|
// itself, and this one does not. Popover ignores it, same as Dialog ignores
|
|
52363
52571
|
// marginWithAnchor.
|
|
52364
|
-
|
|
52572
|
+
dockedOnSmallTouchScreen,
|
|
52365
52573
|
animation,
|
|
52366
52574
|
...rest
|
|
52367
52575
|
} = props;
|
|
@@ -52409,7 +52617,7 @@ const PickerContentInsidePopup = props => {
|
|
|
52409
52617
|
expand: isPopover ? undefined : dialogExpand,
|
|
52410
52618
|
expandX: isPopover ? undefined : dialogExpandX,
|
|
52411
52619
|
expandY: isPopover ? undefined : dialogExpandY,
|
|
52412
|
-
|
|
52620
|
+
dockedOnSmallTouchScreen: isPopover ? undefined : dockedOnSmallTouchScreen,
|
|
52413
52621
|
children: jsx(PopupModeContext.Provider, {
|
|
52414
52622
|
value: mode,
|
|
52415
52623
|
children: children
|
|
@@ -54087,7 +54295,7 @@ const css$v = /* css */`
|
|
|
54087
54295
|
|
|
54088
54296
|
/* Same reasoning, for the corners: a dialog squares off whatever corner
|
|
54089
54297
|
lands on its container's own (see the data-flush-* rules in dialog.jsx —
|
|
54090
|
-
a bottom sheet from
|
|
54298
|
+
a bottom sheet from dockedOnSmallTouchScreen squares its two bottom ones). A list
|
|
54091
54299
|
drawn right against that corner has to square the same one, otherwise its
|
|
54092
54300
|
own radius carves a notch out of the popup's square corner. Direct child
|
|
54093
54301
|
only: any deeper and the list is presumably inset from the popup's edge,
|
|
@@ -59154,14 +59362,25 @@ installImportMetaCssBuild(import.meta);const css$r = /* css */`
|
|
|
59154
59362
|
--x-picker-border-color: var(--callout-color);
|
|
59155
59363
|
}
|
|
59156
59364
|
|
|
59365
|
+
/* A variant states what the caller did NOT: it moves the DEFAULTS
|
|
59366
|
+
(--picker-*) and never the resolved values (--x-picker-*), so a
|
|
59367
|
+
backgroundColor/borderColor/padding prop — which lands inline on this
|
|
59368
|
+
same element — still wins. The per-state defaults are re-pointed at the
|
|
59369
|
+
base one too, otherwise the @layer formulas (hover = 5% black over the
|
|
59370
|
+
background, disabled = 5% grey) would repaint a box the variant just
|
|
59371
|
+
took away. */
|
|
59157
59372
|
&[data-variant="icon"] {
|
|
59158
|
-
--
|
|
59159
|
-
--
|
|
59160
|
-
--x-picker-padding-bottom: 0;
|
|
59161
|
-
--x-picker-padding-left: 0;
|
|
59373
|
+
--picker-padding-x-default: 0;
|
|
59374
|
+
--picker-padding-y-default: 0;
|
|
59162
59375
|
--picker-border-width: 0px; /* must carry a unit (px) — used in calc() to offset the custom input overlay */
|
|
59163
|
-
--
|
|
59164
|
-
--
|
|
59376
|
+
--picker-border-color: transparent;
|
|
59377
|
+
--picker-border-color-hover: var(--picker-border-color);
|
|
59378
|
+
--picker-border-color-readonly: var(--picker-border-color);
|
|
59379
|
+
--picker-border-color-disabled: var(--picker-border-color);
|
|
59380
|
+
--picker-background-color: transparent;
|
|
59381
|
+
--picker-background-color-hover: var(--picker-background-color);
|
|
59382
|
+
--picker-background-color-readonly: var(--picker-background-color);
|
|
59383
|
+
--picker-background-color-disabled: var(--picker-background-color);
|
|
59165
59384
|
--x-picker-icon-color: currentColor;
|
|
59166
59385
|
}
|
|
59167
59386
|
/* discrete: no box at rest, a background on hover — the same word Button
|
|
@@ -59169,31 +59388,35 @@ installImportMetaCssBuild(import.meta);const css$r = /* css */`
|
|
|
59169
59388
|
around it; the chevron in the right slot is what still says it opens. */
|
|
59170
59389
|
&[data-variant="discrete"] {
|
|
59171
59390
|
--picker-border-width: 0px; /* must carry a unit (px) — used in calc() to offset the custom input overlay */
|
|
59172
|
-
--
|
|
59173
|
-
--
|
|
59174
|
-
|
|
59175
|
-
|
|
59176
|
-
|
|
59177
|
-
|
|
59178
|
-
|
|
59179
|
-
|
|
59180
|
-
|
|
59181
|
-
|
|
59182
|
-
|
|
59183
|
-
|
|
59184
|
-
|
|
59185
|
-
|
|
59186
|
-
|
|
59187
|
-
|
|
59391
|
+
--picker-border-color: transparent;
|
|
59392
|
+
--picker-border-color-hover: var(--picker-border-color);
|
|
59393
|
+
--picker-border-color-readonly: var(--picker-border-color);
|
|
59394
|
+
--picker-border-color-disabled: var(--picker-border-color);
|
|
59395
|
+
--picker-background-color: transparent;
|
|
59396
|
+
/* The hover wash is mixed INTO the background instead of replacing it:
|
|
59397
|
+
over the transparent default it is exactly the 8% of currentColor it
|
|
59398
|
+
has always been, and over a backgroundColor the caller gave it darkens
|
|
59399
|
+
that color rather than erasing it. */
|
|
59400
|
+
--picker-background-color-hover: color-mix(
|
|
59401
|
+
in srgb,
|
|
59402
|
+
currentColor 8%,
|
|
59403
|
+
var(--picker-background-color)
|
|
59404
|
+
);
|
|
59405
|
+
--picker-background-color-readonly: var(--picker-background-color);
|
|
59406
|
+
--picker-background-color-disabled: var(--picker-background-color);
|
|
59188
59407
|
}
|
|
59189
59408
|
&[data-variant="headless"] {
|
|
59190
|
-
--
|
|
59191
|
-
--
|
|
59192
|
-
--x-picker-padding-bottom: 0;
|
|
59193
|
-
--x-picker-padding-left: 0;
|
|
59409
|
+
--picker-padding-x-default: 0;
|
|
59410
|
+
--picker-padding-y-default: 0;
|
|
59194
59411
|
--picker-border-width: 0px; /* must carry a unit (px) — used in calc() to offset the custom input overlay */
|
|
59195
|
-
--
|
|
59196
|
-
--
|
|
59412
|
+
--picker-border-color: transparent;
|
|
59413
|
+
--picker-border-color-hover: var(--picker-border-color);
|
|
59414
|
+
--picker-border-color-readonly: var(--picker-border-color);
|
|
59415
|
+
--picker-border-color-disabled: var(--picker-border-color);
|
|
59416
|
+
--picker-background-color: transparent;
|
|
59417
|
+
--picker-background-color-hover: var(--picker-background-color);
|
|
59418
|
+
--picker-background-color-readonly: var(--picker-background-color);
|
|
59419
|
+
--picker-background-color-disabled: var(--picker-background-color);
|
|
59197
59420
|
--x-picker-icon-color: currentColor;
|
|
59198
59421
|
|
|
59199
59422
|
.navi_picker_box {
|
|
@@ -71079,5 +71302,5 @@ const UserSvg = () => jsx("svg", {
|
|
|
71079
71302
|
})
|
|
71080
71303
|
});
|
|
71081
71304
|
|
|
71082
|
-
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, Paragraph, Picker, Popover, Popup, Quantity, RadioGroup, Route, RouteTravel, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, SpinGroup, StarSvg, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, TimeRangeSpin, TimeSpin, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership,
|
|
71305
|
+
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, Paragraph, Picker, Popover, Popup, Quantity, RadioGroup, Route, RouteTravel, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, SpinGroup, StarSvg, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, TimeRangeSpin, TimeSpin, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, compareTwoJsValues, createAction, createAvailableConstraint, createI18n, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineNaviConfirmPopupOptions, detectHorizontalOverflow, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutRequestClose, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, usePopupMode, useRouteStatus, useRunOnMount, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
|
|
71083
71306
|
//# sourceMappingURL=jsenv_navi.js.map
|