@jsenv/navi 0.29.10 → 0.29.11
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 +237 -34
- package/dist/jsenv_navi.js.map +13 -11
- package/docs/MOBILE_LAYOUT_PITFALLS.md +69 -14
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -9742,7 +9742,7 @@ const setupNetworkMonitoring = () => {
|
|
|
9742
9742
|
};
|
|
9743
9743
|
setupNetworkMonitoring();
|
|
9744
9744
|
|
|
9745
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
9745
|
+
installImportMetaCssBuild(import.meta);const css$Y = /* css */`
|
|
9746
9746
|
.navi_loading_indicator_fluid_container {
|
|
9747
9747
|
position: relative;
|
|
9748
9748
|
display: flex;
|
|
@@ -9774,7 +9774,7 @@ const LoadingIndicatorFluid = ({
|
|
|
9774
9774
|
visuallyHidden,
|
|
9775
9775
|
...rest
|
|
9776
9776
|
}) => {
|
|
9777
|
-
import.meta.css = [css$
|
|
9777
|
+
import.meta.css = [css$Y, "@jsenv/navi/src/graphic/loading/loading_indicator_fluid.jsx"];
|
|
9778
9778
|
const ref = useRef(null);
|
|
9779
9779
|
// The container dimensions can be deduced from the ref itself as the indicator is absolute inset 0
|
|
9780
9780
|
const [containerWidth, setContainerWidth] = useState(0);
|
|
@@ -9979,7 +9979,7 @@ const LoadingRectangleSvg = ({
|
|
|
9979
9979
|
});
|
|
9980
9980
|
};
|
|
9981
9981
|
|
|
9982
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
9982
|
+
installImportMetaCssBuild(import.meta);const css$X = /* css */`
|
|
9983
9983
|
.navi_loading_outline_wrapper {
|
|
9984
9984
|
position: absolute;
|
|
9985
9985
|
/* Controls place the outline slightly outside their box, right on top of
|
|
@@ -10016,7 +10016,7 @@ installImportMetaCssBuild(import.meta);const css$W = /* css */`
|
|
|
10016
10016
|
}
|
|
10017
10017
|
`;
|
|
10018
10018
|
const LoadingOutline = props => {
|
|
10019
|
-
import.meta.css = [css$
|
|
10019
|
+
import.meta.css = [css$X, "@jsenv/navi/src/graphic/loading/loading_outline.jsx"];
|
|
10020
10020
|
if (props.containerRef) {
|
|
10021
10021
|
const container = props.containerRef.current;
|
|
10022
10022
|
if (!container) {
|
|
@@ -10341,7 +10341,7 @@ const selectByTextStrings = (element, range, startText, endText) => {
|
|
|
10341
10341
|
};
|
|
10342
10342
|
|
|
10343
10343
|
installImportMetaCssBuild(import.meta);// https://jsfiddle.net/v5xzJ/4/
|
|
10344
|
-
const css$
|
|
10344
|
+
const css$W = /* css */`
|
|
10345
10345
|
@layer navi {
|
|
10346
10346
|
.navi_text {
|
|
10347
10347
|
&[data-skeleton] {
|
|
@@ -10847,7 +10847,7 @@ const TextShrinkWrap = props => {
|
|
|
10847
10847
|
});
|
|
10848
10848
|
};
|
|
10849
10849
|
const TextUI = props => {
|
|
10850
|
-
import.meta.css = [css$
|
|
10850
|
+
import.meta.css = [css$W, "@jsenv/navi/src/text/text.jsx"];
|
|
10851
10851
|
let {
|
|
10852
10852
|
ref,
|
|
10853
10853
|
spacing,
|
|
@@ -13561,7 +13561,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
13561
13561
|
* - Arrow automatically shows when pointing at a valid anchor element
|
|
13562
13562
|
* - Centers in viewport when no anchor element provided or anchor is too big
|
|
13563
13563
|
*/
|
|
13564
|
-
const css$
|
|
13564
|
+
const css$V = /* css */`
|
|
13565
13565
|
@layer navi {
|
|
13566
13566
|
.navi_callout {
|
|
13567
13567
|
/* A callout is parented to what it explains, so it inherits from it — and
|
|
@@ -13781,7 +13781,7 @@ const openCallout = (message, {
|
|
|
13781
13781
|
skipFocus = false,
|
|
13782
13782
|
debug = () => {}
|
|
13783
13783
|
} = {}) => {
|
|
13784
|
-
import.meta.css = [css$
|
|
13784
|
+
import.meta.css = [css$V, "@jsenv/navi/src/control/rules/callout/callout.js"];
|
|
13785
13785
|
if (debug === true) {
|
|
13786
13786
|
debug = (e, ...args) => console.debug(`"${e.type}" -> `, ...args);
|
|
13787
13787
|
}
|
|
@@ -22859,7 +22859,7 @@ const getAssociatedLabels = element => {
|
|
|
22859
22859
|
return [];
|
|
22860
22860
|
};
|
|
22861
22861
|
|
|
22862
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
22862
|
+
installImportMetaCssBuild(import.meta);const css$U = /* css */`
|
|
22863
22863
|
@layer navi {
|
|
22864
22864
|
.navi_button {
|
|
22865
22865
|
--button-border-radius: var(--navi-control-border-radius);
|
|
@@ -23252,7 +23252,7 @@ installImportMetaCssBuild(import.meta);const css$T = /* css */`
|
|
|
23252
23252
|
}
|
|
23253
23253
|
`;
|
|
23254
23254
|
const ButtonUI = props => {
|
|
23255
|
-
import.meta.css = [css$
|
|
23255
|
+
import.meta.css = [css$U, "@jsenv/navi/src/control/input/button_ui.jsx"];
|
|
23256
23256
|
const {
|
|
23257
23257
|
ref,
|
|
23258
23258
|
// href/link
|
|
@@ -25380,7 +25380,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
25380
25380
|
* reaches the real container.
|
|
25381
25381
|
*/
|
|
25382
25382
|
let openLocalDialogCount = 0;
|
|
25383
|
-
const css$
|
|
25383
|
+
const css$T = /* css */`
|
|
25384
25384
|
@layer navi {
|
|
25385
25385
|
.navi_dialog {
|
|
25386
25386
|
/* Min gap between the dialog and the edges of its container. Written
|
|
@@ -25790,7 +25790,7 @@ const css$S = /* css */`
|
|
|
25790
25790
|
* @param {import("ignore:preact").ComponentChildren} props.children
|
|
25791
25791
|
*/
|
|
25792
25792
|
const Dialog = props => {
|
|
25793
|
-
import.meta.css = [css$
|
|
25793
|
+
import.meta.css = [css$T, "@jsenv/navi/src/layout/dialog.jsx"];
|
|
25794
25794
|
if (props.openController) {
|
|
25795
25795
|
return jsx(ControlledDialog, {
|
|
25796
25796
|
...props
|
|
@@ -26608,7 +26608,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
26608
26608
|
* and applied.
|
|
26609
26609
|
*/
|
|
26610
26610
|
let openLocalPopoverCount = 0;
|
|
26611
|
-
const css$
|
|
26611
|
+
const css$S = /* css */`
|
|
26612
26612
|
@layer navi {
|
|
26613
26613
|
.navi_popover {
|
|
26614
26614
|
/* soft: user-configurable preferred max-height. Kept as a *default*
|
|
@@ -26978,7 +26978,7 @@ const css$R = /* css */`
|
|
|
26978
26978
|
* @param {import("ignore:preact").ComponentChildren} props.children
|
|
26979
26979
|
*/
|
|
26980
26980
|
const Popover = props => {
|
|
26981
|
-
import.meta.css = [css$
|
|
26981
|
+
import.meta.css = [css$S, "@jsenv/navi/src/layout/popover.jsx"];
|
|
26982
26982
|
if (props.openController) {
|
|
26983
26983
|
return jsx(ControlledPopover, {
|
|
26984
26984
|
...props
|
|
@@ -27942,7 +27942,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
27942
27942
|
* event, and a caller replacing the body entirely then has one protocol to
|
|
27943
27943
|
* follow — `--navi-confirm` for yes, anything that closes for no.
|
|
27944
27944
|
*/
|
|
27945
|
-
const css$
|
|
27945
|
+
const css$R = /* css */`
|
|
27946
27946
|
/* The width lives on the body rather than on the popup, so that custom
|
|
27947
27947
|
content (which replaces this body entirely) sizes itself instead of
|
|
27948
27948
|
inheriting a ceiling meant for a sentence-long question. */
|
|
@@ -28079,7 +28079,7 @@ const ConfirmPopup = ({
|
|
|
28079
28079
|
onAnswer,
|
|
28080
28080
|
onClosed
|
|
28081
28081
|
}) => {
|
|
28082
|
-
import.meta.css = [css$
|
|
28082
|
+
import.meta.css = [css$R, "@jsenv/navi/src/action/confirm_popup.jsx"];
|
|
28083
28083
|
const {
|
|
28084
28084
|
mode,
|
|
28085
28085
|
confirmLabel,
|
|
@@ -28163,7 +28163,7 @@ const defaultBody = (message, {
|
|
|
28163
28163
|
});
|
|
28164
28164
|
};
|
|
28165
28165
|
|
|
28166
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
28166
|
+
installImportMetaCssBuild(import.meta);const css$Q = /* css */`
|
|
28167
28167
|
.action_error {
|
|
28168
28168
|
margin-top: 0;
|
|
28169
28169
|
margin-bottom: 20px;
|
|
@@ -28188,7 +28188,7 @@ const ActionRenderer = ({
|
|
|
28188
28188
|
children,
|
|
28189
28189
|
disabled
|
|
28190
28190
|
}) => {
|
|
28191
|
-
import.meta.css = [css$
|
|
28191
|
+
import.meta.css = [css$Q, "@jsenv/navi/src/action/action_renderer.jsx"];
|
|
28192
28192
|
if (action === undefined) {
|
|
28193
28193
|
throw new Error("ActionRenderer requires an action to render, but none was provided.");
|
|
28194
28194
|
}
|
|
@@ -35234,7 +35234,7 @@ const PhoneSvg = () => {
|
|
|
35234
35234
|
};
|
|
35235
35235
|
|
|
35236
35236
|
installImportMetaCssBuild(import.meta);// # TextAnchor — how it works
|
|
35237
|
-
const css$
|
|
35237
|
+
const css$P = /* css */`
|
|
35238
35238
|
.navi_text_anchor {
|
|
35239
35239
|
vertical-align: baseline;
|
|
35240
35240
|
user-select: none;
|
|
@@ -35269,7 +35269,7 @@ const TextAnchor = ({
|
|
|
35269
35269
|
textSize,
|
|
35270
35270
|
lineLayout
|
|
35271
35271
|
}) => {
|
|
35272
|
-
import.meta.css = [css$
|
|
35272
|
+
import.meta.css = [css$P, "@jsenv/navi/src/text/text_anchor.jsx"];
|
|
35273
35273
|
const anchorRef = useRef();
|
|
35274
35274
|
|
|
35275
35275
|
// Plain useLayoutEffect would also fire while an ancestor dialog/popover
|
|
@@ -35384,7 +35384,7 @@ const computeTopOffset = ({
|
|
|
35384
35384
|
};
|
|
35385
35385
|
const charTopCanvas = document.createElement("canvas");
|
|
35386
35386
|
|
|
35387
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
35387
|
+
installImportMetaCssBuild(import.meta);const css$O = /* css */`
|
|
35388
35388
|
@layer navi {
|
|
35389
35389
|
/* Ensure data attributes from box.jsx can win to update display */
|
|
35390
35390
|
.navi_icon {
|
|
@@ -35542,7 +35542,7 @@ const Icon = ({
|
|
|
35542
35542
|
fillLine,
|
|
35543
35543
|
...props
|
|
35544
35544
|
}) => {
|
|
35545
|
-
import.meta.css = [css$
|
|
35545
|
+
import.meta.css = [css$O, "@jsenv/navi/src/text/icon.jsx"];
|
|
35546
35546
|
const innerChildren = href ? jsx("svg", {
|
|
35547
35547
|
width: "100%",
|
|
35548
35548
|
height: "100%",
|
|
@@ -35695,7 +35695,7 @@ const useDimColorWhen = (elementRef, shouldDim) => {
|
|
|
35695
35695
|
});
|
|
35696
35696
|
};
|
|
35697
35697
|
|
|
35698
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
35698
|
+
installImportMetaCssBuild(import.meta);const css$N = /* css */`
|
|
35699
35699
|
@layer navi {
|
|
35700
35700
|
.navi_link {
|
|
35701
35701
|
--link-border-radius: unset;
|
|
@@ -36134,7 +36134,7 @@ Object.assign(PSEUDO_CLASSES, {
|
|
|
36134
36134
|
* @param {boolean} [props.readOnly]
|
|
36135
36135
|
*/
|
|
36136
36136
|
const Link = props => {
|
|
36137
|
-
import.meta.css = [css$
|
|
36137
|
+
import.meta.css = [css$N, "@jsenv/navi/src/nav/link/link.jsx"];
|
|
36138
36138
|
if (props.route) {
|
|
36139
36139
|
return jsx(LinkWithRoute, {
|
|
36140
36140
|
...props
|
|
@@ -36369,7 +36369,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
36369
36369
|
* TabList component with support for horizontal and vertical layouts
|
|
36370
36370
|
* https://dribbble.com/search/tabs
|
|
36371
36371
|
*/
|
|
36372
|
-
const css$
|
|
36372
|
+
const css$M = /* css */`
|
|
36373
36373
|
@layer navi {
|
|
36374
36374
|
.navi_nav {
|
|
36375
36375
|
--nav-border: none;
|
|
@@ -36544,7 +36544,7 @@ const Nav = ({
|
|
|
36544
36544
|
// "before" or "after": which side the panel sits on, turning the nav into folder tabs
|
|
36545
36545
|
...props
|
|
36546
36546
|
}) => {
|
|
36547
|
-
import.meta.css = [css$
|
|
36547
|
+
import.meta.css = [css$M, "@jsenv/navi/src/nav/link/nav.jsx"];
|
|
36548
36548
|
children = toChildArray(children);
|
|
36549
36549
|
return jsx(Box, {
|
|
36550
36550
|
as: "nav",
|
|
@@ -36936,7 +36936,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
36936
36936
|
* Border width participates in layout (it is added to the tab and page
|
|
36937
36937
|
* padding): a thick border grows the binder rather than eating into the text.
|
|
36938
36938
|
*/
|
|
36939
|
-
const css$
|
|
36939
|
+
const css$L = /* css */`
|
|
36940
36940
|
@layer navi {
|
|
36941
36941
|
.navi_binder {
|
|
36942
36942
|
--binder-border-width: var(--navi-control-border-width);
|
|
@@ -37249,7 +37249,7 @@ const Binder = ({
|
|
|
37249
37249
|
pagePadding,
|
|
37250
37250
|
...props
|
|
37251
37251
|
}) => {
|
|
37252
|
-
import.meta.css = [css$
|
|
37252
|
+
import.meta.css = [css$L, "@jsenv/navi/src/nav/binder/binder.jsx"];
|
|
37253
37253
|
const items = toChildArray(children).map((child, index) => {
|
|
37254
37254
|
const {
|
|
37255
37255
|
value: itemValue,
|
|
@@ -37671,7 +37671,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
37671
37671
|
* into the size; a box-shadow draws the identical line and stays out of
|
|
37672
37672
|
* layout.
|
|
37673
37673
|
*/
|
|
37674
|
-
const css$
|
|
37674
|
+
const css$K = /* css */`
|
|
37675
37675
|
@layer navi {
|
|
37676
37676
|
:root {
|
|
37677
37677
|
--navi-fixed-bar-width: 56px;
|
|
@@ -37809,7 +37809,7 @@ const FixedBar = ({
|
|
|
37809
37809
|
border = true,
|
|
37810
37810
|
...props
|
|
37811
37811
|
}) => {
|
|
37812
|
-
import.meta.css = [css$
|
|
37812
|
+
import.meta.css = [css$K, "@jsenv/navi/src/layout/fixed_bar/fixed_bar.jsx"];
|
|
37813
37813
|
const defaultRef = useRef();
|
|
37814
37814
|
props.ref = props.ref || defaultRef;
|
|
37815
37815
|
// Whichever of width/height crosses the edge the bar sits on is what the
|
|
@@ -37846,6 +37846,178 @@ const FixedBar = ({
|
|
|
37846
37846
|
});
|
|
37847
37847
|
};
|
|
37848
37848
|
|
|
37849
|
+
/**
|
|
37850
|
+
* Finds the element that is too wide for the page and says which one it is.
|
|
37851
|
+
*
|
|
37852
|
+
* A page that overflows horizontally is a bug wherever it happens, and on
|
|
37853
|
+
* Chrome Android it is a catastrophic one: the layout viewport inflates to the
|
|
37854
|
+
* content and `position: fixed` centering goes with it (see
|
|
37855
|
+
* docs/MOBILE_LAYOUT_PITFALLS.md). The remedy there is a wrapper in
|
|
37856
|
+
* `overflow-x: clip`, and it works — at the price of making the cause
|
|
37857
|
+
* invisible: nothing sticks out anymore, so nothing says a fixed width, a
|
|
37858
|
+
* `min-width` or an unbreakable string is still oversized. This puts the
|
|
37859
|
+
* signal back, without giving up the net.
|
|
37860
|
+
*
|
|
37861
|
+
* What counts as "too wide" is measured against the box that clips, not
|
|
37862
|
+
* against the document: with `clip` there is no scrollable overflow to read
|
|
37863
|
+
* (`scrollWidth` reports none), so the rectangles of the descendants are what
|
|
37864
|
+
* tells.
|
|
37865
|
+
*
|
|
37866
|
+
* Two things are deliberately not reported, because they cannot reach the
|
|
37867
|
+
* document:
|
|
37868
|
+
* - anything inside a box that clips or scrolls on its own — a wide table in
|
|
37869
|
+
* its `overflow-x: auto` container is doing exactly what it should;
|
|
37870
|
+
* - anything out of flow in the viewport's own coordinates (`position: fixed`,
|
|
37871
|
+
* the top layer), which contributes nothing to the document's overflow.
|
|
37872
|
+
*/
|
|
37873
|
+
|
|
37874
|
+
|
|
37875
|
+
// Subpixel layout rounds rectangles up on boxes that fit exactly.
|
|
37876
|
+
const OVERFLOW_TOLERANCE = 1;
|
|
37877
|
+
|
|
37878
|
+
const css$J = /* css */ `
|
|
37879
|
+
[data-navi-overflow-x] {
|
|
37880
|
+
outline: 2px dashed #e74c3c;
|
|
37881
|
+
outline-offset: -2px;
|
|
37882
|
+
}
|
|
37883
|
+
`;
|
|
37884
|
+
|
|
37885
|
+
/**
|
|
37886
|
+
* @param {object} [options]
|
|
37887
|
+
* @param {Element} [options.root=document.body] The box the content must fit
|
|
37888
|
+
* in — the wrapper carrying `overflow-x: clip`, when there is one.
|
|
37889
|
+
* @param {boolean} [options.highlight=true] Outline the culprits on screen.
|
|
37890
|
+
* @param {(overflows: Array<{element: Element, overflow: number, side: "left"|"right"}>) => void} [options.onDetect]
|
|
37891
|
+
* Replaces the default console warning.
|
|
37892
|
+
* @returns {() => void} Stops watching.
|
|
37893
|
+
*/
|
|
37894
|
+
const detectHorizontalOverflow = ({
|
|
37895
|
+
root = document.body,
|
|
37896
|
+
highlight = true,
|
|
37897
|
+
onDetect = warnOverflows,
|
|
37898
|
+
} = {}) => {
|
|
37899
|
+
let styleEl = null;
|
|
37900
|
+
if (highlight) {
|
|
37901
|
+
styleEl = document.createElement("style");
|
|
37902
|
+
styleEl.textContent = css$J;
|
|
37903
|
+
document.head.appendChild(styleEl);
|
|
37904
|
+
}
|
|
37905
|
+
|
|
37906
|
+
let highlightedSet = new Set();
|
|
37907
|
+
const detect = () => {
|
|
37908
|
+
const overflows = findOverflows(root);
|
|
37909
|
+
if (highlight) {
|
|
37910
|
+
const nextHighlightedSet = new Set();
|
|
37911
|
+
for (const { element } of overflows) {
|
|
37912
|
+
element.setAttribute("data-navi-overflow-x", "");
|
|
37913
|
+
nextHighlightedSet.add(element);
|
|
37914
|
+
}
|
|
37915
|
+
for (const element of highlightedSet) {
|
|
37916
|
+
if (!nextHighlightedSet.has(element)) {
|
|
37917
|
+
element.removeAttribute("data-navi-overflow-x");
|
|
37918
|
+
}
|
|
37919
|
+
}
|
|
37920
|
+
highlightedSet = nextHighlightedSet;
|
|
37921
|
+
}
|
|
37922
|
+
if (overflows.length) {
|
|
37923
|
+
onDetect(overflows);
|
|
37924
|
+
}
|
|
37925
|
+
};
|
|
37926
|
+
|
|
37927
|
+
// Measuring inside a resize callback is what makes the loop; wait for the
|
|
37928
|
+
// frame that resize produced.
|
|
37929
|
+
let frame = null;
|
|
37930
|
+
const requestDetect = () => {
|
|
37931
|
+
if (frame !== null) {
|
|
37932
|
+
return;
|
|
37933
|
+
}
|
|
37934
|
+
frame = requestAnimationFrame(() => {
|
|
37935
|
+
frame = null;
|
|
37936
|
+
detect();
|
|
37937
|
+
});
|
|
37938
|
+
};
|
|
37939
|
+
|
|
37940
|
+
// Resize catches the window narrowing and the content growing (the root gets
|
|
37941
|
+
// taller); mutations catch a wide element arriving without changing the
|
|
37942
|
+
// root's size.
|
|
37943
|
+
const resizeObserver = new ResizeObserver(requestDetect);
|
|
37944
|
+
resizeObserver.observe(root);
|
|
37945
|
+
const mutationObserver = new MutationObserver(requestDetect);
|
|
37946
|
+
mutationObserver.observe(root, { subtree: true, childList: true });
|
|
37947
|
+
requestDetect();
|
|
37948
|
+
|
|
37949
|
+
return () => {
|
|
37950
|
+
resizeObserver.disconnect();
|
|
37951
|
+
mutationObserver.disconnect();
|
|
37952
|
+
if (frame !== null) {
|
|
37953
|
+
cancelAnimationFrame(frame);
|
|
37954
|
+
frame = null;
|
|
37955
|
+
}
|
|
37956
|
+
for (const element of highlightedSet) {
|
|
37957
|
+
element.removeAttribute("data-navi-overflow-x");
|
|
37958
|
+
}
|
|
37959
|
+
highlightedSet.clear();
|
|
37960
|
+
if (styleEl) {
|
|
37961
|
+
styleEl.remove();
|
|
37962
|
+
}
|
|
37963
|
+
};
|
|
37964
|
+
};
|
|
37965
|
+
|
|
37966
|
+
const warnOverflows = (overflows) => {
|
|
37967
|
+
for (const { element, overflow, side } of overflows) {
|
|
37968
|
+
console.warn(
|
|
37969
|
+
`${getElementSignature(element)} overflows the page by ${Math.round(
|
|
37970
|
+
overflow,
|
|
37971
|
+
)}px on the ${side}. Look for a width in px, a min-width, or an unbreakable string; if it is meant to be wider than the screen, give it its own "overflow-x: auto".`,
|
|
37972
|
+
element,
|
|
37973
|
+
);
|
|
37974
|
+
}
|
|
37975
|
+
};
|
|
37976
|
+
|
|
37977
|
+
const findOverflows = (root) => {
|
|
37978
|
+
const rootRect = root.getBoundingClientRect();
|
|
37979
|
+
const rootStyle = getComputedStyle(root);
|
|
37980
|
+
// Only the end side is watched: what sticks out there is what the document
|
|
37981
|
+
// grows to hold, and what inflates the layout viewport. Past the start edge
|
|
37982
|
+
// the content is simply unreachable, and that is where the offscreen
|
|
37983
|
+
// patterns (a label parked at `left: -9999px`) live.
|
|
37984
|
+
const side = rootStyle.direction === "rtl" ? "left" : "right";
|
|
37985
|
+
const overflows = [];
|
|
37986
|
+
const collect = (parentEl) => {
|
|
37987
|
+
for (const el of parentEl.children) {
|
|
37988
|
+
const style = getComputedStyle(el);
|
|
37989
|
+
if (style.display === "none" || style.position === "fixed") {
|
|
37990
|
+
continue;
|
|
37991
|
+
}
|
|
37992
|
+
if (el.hasAttribute("popover") || el.tagName === "DIALOG") {
|
|
37993
|
+
continue;
|
|
37994
|
+
}
|
|
37995
|
+
const rect = el.getBoundingClientRect();
|
|
37996
|
+
if (rect.width === 0 && rect.height === 0) {
|
|
37997
|
+
continue;
|
|
37998
|
+
}
|
|
37999
|
+
const overflow =
|
|
38000
|
+
side === "right"
|
|
38001
|
+
? rect.right - rootRect.right
|
|
38002
|
+
: rootRect.left - rect.left;
|
|
38003
|
+
if (overflow > OVERFLOW_TOLERANCE) {
|
|
38004
|
+
// The outermost box that sticks out is the one to fix; its children
|
|
38005
|
+
// stick out because it does.
|
|
38006
|
+
overflows.push({ element: el, overflow, side });
|
|
38007
|
+
continue;
|
|
38008
|
+
}
|
|
38009
|
+
// A box holding its own horizontal overflow cannot leak into the page,
|
|
38010
|
+
// whatever it holds — a wide table in its own scroll box is right.
|
|
38011
|
+
if (style.overflowX !== "visible") {
|
|
38012
|
+
continue;
|
|
38013
|
+
}
|
|
38014
|
+
collect(el);
|
|
38015
|
+
}
|
|
38016
|
+
};
|
|
38017
|
+
collect(root);
|
|
38018
|
+
return overflows;
|
|
38019
|
+
};
|
|
38020
|
+
|
|
37849
38021
|
const useFocusGroup = (
|
|
37850
38022
|
elementRef,
|
|
37851
38023
|
{
|
|
@@ -47048,7 +47220,7 @@ const css$u = /* css */`
|
|
|
47048
47220
|
around it does. Its own scroll box must then be transparent to
|
|
47049
47221
|
layout — otherwise it would cap the list at a height of its own and
|
|
47050
47222
|
start a second, nested scroll inside the page's. */
|
|
47051
|
-
&[data-scroller
|
|
47223
|
+
&[data-scroller] {
|
|
47052
47224
|
max-height: none;
|
|
47053
47225
|
overflow: visible;
|
|
47054
47226
|
|
|
@@ -47058,6 +47230,14 @@ const css$u = /* css */`
|
|
|
47058
47230
|
}
|
|
47059
47231
|
}
|
|
47060
47232
|
|
|
47233
|
+
/* Scrolling with the page means sticking to the viewport, and a FixedBar
|
|
47234
|
+
is in front of that viewport: without the offset a sticky label lands
|
|
47235
|
+
behind the bar. The bar publishes the room it takes (see
|
|
47236
|
+
fixed_bar_space.js) and it is 0px when there is no bar. */
|
|
47237
|
+
&[data-scroller="document"] {
|
|
47238
|
+
--x-list-group-label-top: var(--navi-fixed-bar-space-top, 0px);
|
|
47239
|
+
}
|
|
47240
|
+
|
|
47061
47241
|
&[data-expand-x] {
|
|
47062
47242
|
width: 100%;
|
|
47063
47243
|
}
|
|
@@ -47416,7 +47596,7 @@ const css$u = /* css */`
|
|
|
47416
47596
|
|
|
47417
47597
|
.navi_list_item_group_label {
|
|
47418
47598
|
position: sticky;
|
|
47419
|
-
top:
|
|
47599
|
+
top: var(--list-group-label-top, var(--x-list-group-label-top, 0px));
|
|
47420
47600
|
z-index: 1;
|
|
47421
47601
|
display: block;
|
|
47422
47602
|
background-color: var(--list-group-label-background-color);
|
|
@@ -47659,7 +47839,7 @@ const ListUI = props => {
|
|
|
47659
47839
|
baseClassName: "navi_list_container",
|
|
47660
47840
|
popover: popover,
|
|
47661
47841
|
"data-horizontal": horizontal ? "" : undefined,
|
|
47662
|
-
"data-scroller": scroller
|
|
47842
|
+
"data-scroller": getScrollerAttribute(scroller),
|
|
47663
47843
|
"data-expand-x": expandX || expand ? "" : undefined,
|
|
47664
47844
|
"data-expand-y": expandY || expand ? "" : undefined,
|
|
47665
47845
|
expandX: expandX,
|
|
@@ -47918,6 +48098,7 @@ const useListScrollSync = ({
|
|
|
47918
48098
|
setScrollerElResolved(current => current === scrollerElNow ? current : scrollerElNow);
|
|
47919
48099
|
};
|
|
47920
48100
|
useLayoutEffect(resolveScroller);
|
|
48101
|
+
useStickyScrollportWarning();
|
|
47921
48102
|
|
|
47922
48103
|
// The row the scroll holds onto across a change of geometry, and where it
|
|
47923
48104
|
// sat when that change was decided. Captured at the two moments the list
|
|
@@ -48695,6 +48876,28 @@ const getScrollerViewportRect = scrollerEl => {
|
|
|
48695
48876
|
}
|
|
48696
48877
|
return scrollerEl.getBoundingClientRect();
|
|
48697
48878
|
};
|
|
48879
|
+
const useStickyScrollportWarning = (ref, scroller) => {
|
|
48880
|
+
useRef(false);
|
|
48881
|
+
useLayoutEffect(() => {
|
|
48882
|
+
{
|
|
48883
|
+
return;
|
|
48884
|
+
}
|
|
48885
|
+
});
|
|
48886
|
+
};
|
|
48887
|
+
|
|
48888
|
+
// The CSS needs to tell "the page scrolls me" from "some box around me
|
|
48889
|
+
// scrolls me": only the first one sticks to the viewport, where the fixed bars
|
|
48890
|
+
// are.
|
|
48891
|
+
const getScrollerAttribute = scroller => {
|
|
48892
|
+
if (scroller === "self") {
|
|
48893
|
+
return undefined;
|
|
48894
|
+
}
|
|
48895
|
+
if (scroller === "document") {
|
|
48896
|
+
return "document";
|
|
48897
|
+
}
|
|
48898
|
+
return "parent";
|
|
48899
|
+
};
|
|
48900
|
+
|
|
48698
48901
|
// scroller="parent": the list virtualizes against the scroll box it lives in
|
|
48699
48902
|
// instead of one of its own. Which box that is can only be measured, and a
|
|
48700
48903
|
// measurement holds for the geometry it was taken on — see resolveScroller in
|
|
@@ -62783,5 +62986,5 @@ const UserSvg = () => jsx("svg", {
|
|
|
62783
62986
|
})
|
|
62784
62987
|
});
|
|
62785
62988
|
|
|
62786
|
-
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, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, StarSvg, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, coarsePointerSignal, compareTwoJsValues, createAction, createAvailableConstraint, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineNaviConfirmPopupOptions, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isToday, languagesSignal, localStorageSignal, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setupRoutes, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, 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, valueInLocalStorage, windowWidthSignal };
|
|
62989
|
+
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, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, StarSvg, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, coarsePointerSignal, compareTwoJsValues, createAction, createAvailableConstraint, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineNaviConfirmPopupOptions, detectHorizontalOverflow, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isToday, languagesSignal, localStorageSignal, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setupRoutes, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, 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, valueInLocalStorage, windowWidthSignal };
|
|
62787
62990
|
//# sourceMappingURL=jsenv_navi.js.map
|