@jsenv/navi 0.29.75 → 0.29.77
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 +94 -10
- package/dist/jsenv_navi.js.map +8 -7
- package/docs/AI_INSTRUCTIONS.md +11 -0
- package/docs/dialog_shape.md +223 -0
- package/docs/z_index.md +35 -9
- package/package.json +2 -2
package/dist/jsenv_navi.js
CHANGED
|
@@ -60,7 +60,9 @@ const css$12 = /* css */`
|
|
|
60
60
|
what the page positioned itself, which loses to DOM order otherwise
|
|
61
61
|
(a sticky part is written before what scrolls under it). Box applies
|
|
62
62
|
it by default, isolated, and lets a call site write auto back:
|
|
63
|
-
--box-header-z-index / --box-footer-z-index.
|
|
63
|
+
--box-header-z-index / --box-footer-z-index. <Box sticky> gets it from
|
|
64
|
+
the prop itself, for the same reason and with the same way out (an
|
|
65
|
+
explicit zIndex, "auto" included).
|
|
64
66
|
|
|
65
67
|
"While stuck" is the condition the name states, and it costs something
|
|
66
68
|
to ignore: a sticky part at rest is a block in the flow with nothing
|
|
@@ -16935,6 +16937,28 @@ const DIMENSION_PROPS = {
|
|
|
16935
16937
|
return { transform: `scaleZ(${value})` };
|
|
16936
16938
|
},
|
|
16937
16939
|
};
|
|
16940
|
+
const applyPositionSticky = applyToCssPropWhenTruthy(
|
|
16941
|
+
"position",
|
|
16942
|
+
"sticky",
|
|
16943
|
+
"static",
|
|
16944
|
+
);
|
|
16945
|
+
// A sticky box is one something scrolls under, which is what
|
|
16946
|
+
// --navi-z-index-sticky names; without it the box is a positioned element at
|
|
16947
|
+
// z-index: auto and loses to anything the page raised — a Group member holding
|
|
16948
|
+
// focus (2) is seen passing in front of a sticky submit bar. Like Box's own
|
|
16949
|
+
// header/footer, the band applies always and not only while stuck: a box
|
|
16950
|
+
// written by an app is the generic case, it cannot read its own stuck state
|
|
16951
|
+
// (see docs/z_index.md), and dropping to auto loses to a single
|
|
16952
|
+
// position: relative. An explicit zIndex (including zIndex="auto") wins.
|
|
16953
|
+
const stickyZIndex = (styleContext) => {
|
|
16954
|
+
if (
|
|
16955
|
+
styleContext.styles.zIndex !== undefined ||
|
|
16956
|
+
styleContext.remainingProps.zIndex !== undefined
|
|
16957
|
+
) {
|
|
16958
|
+
return null;
|
|
16959
|
+
}
|
|
16960
|
+
return { zIndex: "var(--navi-z-index-sticky)" };
|
|
16961
|
+
};
|
|
16938
16962
|
const POSITION_PROPS = {
|
|
16939
16963
|
// For row, selfAlignX uses auto margins for positioning
|
|
16940
16964
|
// NOTE: Auto margins only work effectively for positioning individual items.
|
|
@@ -17002,11 +17026,22 @@ const POSITION_PROPS = {
|
|
|
17002
17026
|
}
|
|
17003
17027
|
return undefined;
|
|
17004
17028
|
},
|
|
17005
|
-
position:
|
|
17029
|
+
position: (value, styleContext) => {
|
|
17030
|
+
if (value === "sticky") {
|
|
17031
|
+
return { position: "sticky", ...stickyZIndex(styleContext) };
|
|
17032
|
+
}
|
|
17033
|
+
return { position: value };
|
|
17034
|
+
},
|
|
17006
17035
|
absolute: applyToCssPropWhenTruthy("position", "absolute", "static"),
|
|
17007
17036
|
relative: applyToCssPropWhenTruthy("position", "relative", "static"),
|
|
17008
17037
|
fixed: applyToCssPropWhenTruthy("position", "fixed", "static"),
|
|
17009
|
-
sticky:
|
|
17038
|
+
sticky: (value, styleContext) => {
|
|
17039
|
+
const positionStyles = applyPositionSticky(value, styleContext);
|
|
17040
|
+
if (!value) {
|
|
17041
|
+
return positionStyles;
|
|
17042
|
+
}
|
|
17043
|
+
return { ...positionStyles, ...stickyZIndex(styleContext) };
|
|
17044
|
+
},
|
|
17010
17045
|
zIndex: PASS_THROUGH,
|
|
17011
17046
|
// Keeps the zIndex values used inside this box local to it — see
|
|
17012
17047
|
// docs/z_index.md: a z-index that opens no stacking context competes with
|
|
@@ -30219,6 +30254,29 @@ const css$X = /* css */`
|
|
|
30219
30254
|
outline-color: var(--dialog-outline-color);
|
|
30220
30255
|
outline-offset: 0;
|
|
30221
30256
|
box-shadow: var(--dialog-box-shadow);
|
|
30257
|
+
|
|
30258
|
+
/* A gesture landing on the dialog belongs to the dialog: what it cannot
|
|
30259
|
+
scroll (a short body, an axis with nowhere to go) must not travel to
|
|
30260
|
+
whatever is behind. */
|
|
30261
|
+
overscroll-behavior: none;
|
|
30262
|
+
|
|
30263
|
+
/* Docking answers a different question than --dialog-max-width: a sheet
|
|
30264
|
+
spans its container's full width, flush against the two side edges —
|
|
30265
|
+
that shape IS the mode — while the caller's ceiling was an answer about
|
|
30266
|
+
the *centered* box ("do not sprawl on a wide window"). Applying it here
|
|
30267
|
+
turns the sheet into a small floating box that no longer touches the
|
|
30268
|
+
edges it was docked to, so it is dropped out of the clamp entirely; the
|
|
30269
|
+
container ceiling still holds. --dialog-min-width needs no such rule:
|
|
30270
|
+
the floor is below the full width a docked dialog takes, so it stops
|
|
30271
|
+
mattering on its own. Height is untouched — a sheet is content-tall, not
|
|
30272
|
+
container-tall (expandY cancels docking outright), so --dialog-max-height
|
|
30273
|
+
still means what it meant. */
|
|
30274
|
+
&[data-docked] {
|
|
30275
|
+
--x-dialog-max-width: min(
|
|
30276
|
+
var(--container-position-remaining-width, var(--dialog-maxmax-width)),
|
|
30277
|
+
var(--dialog-maxmax-width)
|
|
30278
|
+
);
|
|
30279
|
+
}
|
|
30222
30280
|
/* The clamped max, not --dialog-maxmax-*: that one is the viewport minus
|
|
30223
30281
|
the spacing, which is only the real ceiling for layer="top". A local
|
|
30224
30282
|
dialog is confined to its positioned ancestor, whose size reaches here
|
|
@@ -30459,7 +30517,15 @@ const css$X = /* css */`
|
|
|
30459
30517
|
* from where the finger just tapped, and size alone would dock a narrow
|
|
30460
30518
|
* desktop window, which is still a mouse. It supplies defaults for
|
|
30461
30519
|
* `positionArea`, `marginWithContainer`, `expandX` and `scrollCapture`, so
|
|
30462
|
-
* any of them can still be pinned explicitly
|
|
30520
|
+
* any of them can still be pinned explicitly — including `expandX={false}`,
|
|
30521
|
+
* which opts the docked dialog out of the full-width stretch and leaves it a
|
|
30522
|
+
* floating box at the bottom. It also withdraws `maxWidth` while docked: a
|
|
30523
|
+
* sheet is container-wide by definition, and a `maxWidth` is an answer about
|
|
30524
|
+
* the *centered* shape, so the two can be stated together (`maxWidth="16rem"
|
|
30525
|
+
* dockedOnSmallTouchScreen`) and each applies where it means something.
|
|
30526
|
+
* `minWidth` needs no such rule — its floor is below the full width — and
|
|
30527
|
+
* `maxHeight`/`minHeight` keep applying, a sheet being content-tall.
|
|
30528
|
+
* Ignored entirely when `expandY`
|
|
30463
30529
|
* (or `expand`) is set: a dialog already filling the height is on the bottom
|
|
30464
30530
|
* edge docking would bring it to, so docking could only take away the shape
|
|
30465
30531
|
* the caller asked for. Re-resolves live as the pointer
|
|
@@ -30481,7 +30547,10 @@ const css$X = /* css */`
|
|
|
30481
30547
|
* @param {boolean} [props.expand] - Shorthand for both `expandX` and `expandY`.
|
|
30482
30548
|
* @param {boolean} [props.expandX] - Stretches the dialog to the full width its
|
|
30483
30549
|
* container allows (`--dialog-maxmax-width`). Set by
|
|
30484
|
-
* `dockedOnSmallTouchScreen` on a small touch screen
|
|
30550
|
+
* `dockedOnSmallTouchScreen` on a small touch screen — so passing `false`
|
|
30551
|
+
* here also opts out of *that* stretch, leaving a docked dialog a floating
|
|
30552
|
+
* box instead of a flush sheet. To keep the sheet flush and merely cap the
|
|
30553
|
+
* centered shape, use `maxWidth`: docking withdraws it on its own.
|
|
30485
30554
|
* @param {boolean} [props.expandY] - Same, vertically
|
|
30486
30555
|
* (`--dialog-maxmax-height`). Cancels `dockedOnSmallTouchScreen`.
|
|
30487
30556
|
* @param {string|number} [props.marginWithContainer="3appw"] - Minimum gap kept
|
|
@@ -30540,7 +30609,9 @@ const css$X = /* css */`
|
|
|
30540
30609
|
* so it can never push the dialog past `--dialog-maxmax-width` (the
|
|
30541
30610
|
* viewport/container-spacing ceiling) regardless of how large a value is
|
|
30542
30611
|
* passed.
|
|
30543
|
-
* @param {string} [props.maxWidth] - Maps to `--dialog-max-width`.
|
|
30612
|
+
* @param {string} [props.maxWidth] - Maps to `--dialog-max-width`. Describes
|
|
30613
|
+
* the centered shape only: a dialog docked by `dockedOnSmallTouchScreen`
|
|
30614
|
+
* ignores it and stays container-wide.
|
|
30544
30615
|
* @param {string} [props.minHeight] - Maps to `--dialog-min-height`, same
|
|
30545
30616
|
* clamping as `minWidth`.
|
|
30546
30617
|
* @param {string} [props.maxHeight] - Maps to `--dialog-max-height`.
|
|
@@ -31059,7 +31130,11 @@ const useDialogProps = props => {
|
|
|
31059
31130
|
}));
|
|
31060
31131
|
}
|
|
31061
31132
|
if (scrollCapture) {
|
|
31062
|
-
|
|
31133
|
+
// A modal dialog always has its own ::backdrop; the custom renderer has
|
|
31134
|
+
// the backdrop element when it renders one.
|
|
31135
|
+
addCleanup(trapScrollInside(dialogEl, {
|
|
31136
|
+
backdrop: isModal || backdropEl
|
|
31137
|
+
}));
|
|
31063
31138
|
} else if (!isModal) {
|
|
31064
31139
|
// A local dialog is confined to its positioned ancestor, and so is its
|
|
31065
31140
|
// backdrop (inset: 0 covers the scrollport, not the scrolled content):
|
|
@@ -31458,6 +31533,10 @@ const useDialogProps = props => {
|
|
|
31458
31533
|
// scrolling area, so it says so once, here.
|
|
31459
31534
|
"overflow": "auto",
|
|
31460
31535
|
"data-layer": layer,
|
|
31536
|
+
// The sheet shape is live in CSS, not just a set of resolved defaults:
|
|
31537
|
+
// it is what withdraws the caller's --dialog-max-width (see the stylesheet
|
|
31538
|
+
// above), which is an answer about the centered box only.
|
|
31539
|
+
"data-docked": isDocked ? "" : undefined,
|
|
31461
31540
|
"data-expand-x": expandX ? "" : undefined,
|
|
31462
31541
|
"data-expand-y": expandY ? "" : undefined,
|
|
31463
31542
|
"data-flush-top": flushEdges.top ? "" : undefined,
|
|
@@ -32592,7 +32671,9 @@ const usePopoverProps = props => {
|
|
|
32592
32671
|
// here.
|
|
32593
32672
|
};
|
|
32594
32673
|
if (scrollCapture) {
|
|
32595
|
-
addCleanup(trapScrollInside(popoverEl
|
|
32674
|
+
addCleanup(trapScrollInside(popoverEl, {
|
|
32675
|
+
backdrop: backdropEl
|
|
32676
|
+
}));
|
|
32596
32677
|
}
|
|
32597
32678
|
if (focusCapture) {
|
|
32598
32679
|
addCleanup(trapFocusInside(popoverEl, {
|
|
@@ -65867,6 +65948,8 @@ const css$l = /* css */`
|
|
|
65867
65948
|
* positionArea?: string,
|
|
65868
65949
|
* popupWidthFitContent?: boolean,
|
|
65869
65950
|
* popoverMaxHeight?: number | string,
|
|
65951
|
+
* dialogMinWidth?: number | string,
|
|
65952
|
+
* dialogMinHeight?: number | string,
|
|
65870
65953
|
* dialogMaxWidth?: number | string,
|
|
65871
65954
|
* dialogMaxHeight?: number | string,
|
|
65872
65955
|
* dialogExpand?: boolean,
|
|
@@ -65916,7 +65999,8 @@ const css$l = /* css */`
|
|
|
65916
65999
|
* popover; a dialog keeps Dialog's own "center".
|
|
65917
66000
|
*
|
|
65918
66001
|
* Every other prop the Picker's popup answers to is forwarded as-is —
|
|
65919
|
-
* `dockedOnSmallTouchScreen`, `dialogExpand*`, `
|
|
66002
|
+
* `dockedOnSmallTouchScreen`, `dialogExpand*`, `dialogMinWidth`/`Height`,
|
|
66003
|
+
* `dialogMaxWidth`/`Height`,
|
|
65920
66004
|
* `marginWithContainer`, `popoverMode`, `popoverSpacing`, `popupLayer`,
|
|
65921
66005
|
* `popupWidthFitContent`, `popoverMaxHeight`, `backdropVariant`,
|
|
65922
66006
|
* `pointerInteractionOutsideEffect`, `escapeEffect`, `closeOnFocusOut`,
|
|
@@ -66121,7 +66205,7 @@ const SplitButton = props => {
|
|
|
66121
66205
|
// What the Picker's popup answers to — Picker's own popup props, named here so
|
|
66122
66206
|
// a caller reaches all of them through the split button (see picker.jsx's JSDoc
|
|
66123
66207
|
// for what each one says).
|
|
66124
|
-
const POPUP_PROP_SET = new Set(["mode", "popupLayer", "positionArea", "popoverMode", "popoverSpacing", "popupWidthFitContent", "popoverMaxHeight", "dialogMaxWidth", "dialogMaxHeight", "dialogExpand", "dialogExpandX", "dialogExpandY", "dockedOnSmallTouchScreen", "marginWithContainer", "backdropVariant", "pointerInteractionOutsideEffect", "escapeEffect", "closeOnFocusOut", "scrollCapture", "focusCapture", "popupBackgroundColor", "popupBorderRadius", "animation"]);
|
|
66208
|
+
const POPUP_PROP_SET = new Set(["mode", "popupLayer", "positionArea", "popoverMode", "popoverSpacing", "popupWidthFitContent", "popoverMaxHeight", "dialogMinWidth", "dialogMinHeight", "dialogMaxWidth", "dialogMaxHeight", "dialogExpand", "dialogExpandX", "dialogExpandY", "dockedOnSmallTouchScreen", "marginWithContainer", "backdropVariant", "pointerInteractionOutsideEffect", "escapeEffect", "closeOnFocusOut", "scrollCapture", "focusCapture", "popupBackgroundColor", "popupBorderRadius", "animation"]);
|
|
66125
66209
|
const splitPopupProps = props => {
|
|
66126
66210
|
const popupProps = {};
|
|
66127
66211
|
const boxProps = {};
|