@jsenv/navi 0.29.319 → 0.29.320
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/dev/jsenv_navi.js +149 -35
- package/dist/dev/jsenv_navi.js.map +5 -5
- package/dist/jsenv_navi.js +149 -35
- package/dist/jsenv_navi.js.map +5 -5
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -27017,14 +27017,35 @@ browserIntegration.handleActionTask;
|
|
|
27017
27017
|
|
|
27018
27018
|
const NO_OP = () => {};
|
|
27019
27019
|
const NO_ID_GIVEN = [undefined, NO_OP, NO_OP];
|
|
27020
|
+
// What the computed below answers for a key the document state does not hold:
|
|
27021
|
+
// key presence is the flag, and the value under a present key may be anything,
|
|
27022
|
+
// undefined included.
|
|
27023
|
+
const KEY_NOT_IN_STATE = Symbol("key_not_in_state");
|
|
27020
27024
|
const useNavStateBasic = (
|
|
27021
27025
|
id,
|
|
27022
27026
|
{ debug, type = "replace", onLeave, defaultValue } = {},
|
|
27023
27027
|
) => {
|
|
27024
27028
|
// Hooks must be called unconditionally — before the !id early return.
|
|
27025
|
-
|
|
27026
|
-
//
|
|
27027
|
-
|
|
27029
|
+
//
|
|
27030
|
+
// Subscribed to this one key, through a computed, rather than to the state
|
|
27031
|
+
// as a whole: every popup with a nav state reads here, and a document state
|
|
27032
|
+
// is written whenever any of them opens — a list of forty names each with a
|
|
27033
|
+
// tooltip would re-render forty pickers, chains included, for the sheet
|
|
27034
|
+
// around them opening. The computed only wakes this component when what
|
|
27035
|
+
// sits under its own key changes.
|
|
27036
|
+
const keyValueComputed = useMemo(
|
|
27037
|
+
() =>
|
|
27038
|
+
computed(() => {
|
|
27039
|
+
const state = documentStateSignal.value;
|
|
27040
|
+
if (id && state && Object.hasOwn(state, id)) {
|
|
27041
|
+
return state[id];
|
|
27042
|
+
}
|
|
27043
|
+
return KEY_NOT_IN_STATE;
|
|
27044
|
+
}),
|
|
27045
|
+
[id],
|
|
27046
|
+
);
|
|
27047
|
+
const keyValue = keyValueComputed.value;
|
|
27048
|
+
const keyInState = keyValue !== KEY_NOT_IN_STATE;
|
|
27028
27049
|
const onLeaveRef = useRef(onLeave);
|
|
27029
27050
|
onLeaveRef.current = onLeave;
|
|
27030
27051
|
const prevKeyInStateRef = useRef(keyInState);
|
|
@@ -27054,7 +27075,7 @@ const useNavStateBasic = (
|
|
|
27054
27075
|
effectiveType = "replace";
|
|
27055
27076
|
}
|
|
27056
27077
|
|
|
27057
|
-
const currentValue = keyInState ?
|
|
27078
|
+
const currentValue = keyInState ? keyValue : defaultValue;
|
|
27058
27079
|
|
|
27059
27080
|
if (debug) {
|
|
27060
27081
|
console.debug(`useNavState(${id}) current value is ${currentValue}`);
|
|
@@ -34565,6 +34586,18 @@ const MOUNT_DEFAULT = "from-first-open";
|
|
|
34565
34586
|
const popupsMountingContentForOpen = new Set();
|
|
34566
34587
|
const isMountingContentForOpen = (popupElement) =>
|
|
34567
34588
|
popupsMountingContentForOpen.has(popupElement);
|
|
34589
|
+
// The popup being built that holds `element` somewhere below it, or null. For
|
|
34590
|
+
// an element whose own openable ancestor is something else (a closed trigger
|
|
34591
|
+
// inside the popup): what the layout would say about it is what it says about
|
|
34592
|
+
// the whole popup — nothing is on screen there yet.
|
|
34593
|
+
const findPopupMountingContentAround = (element) => {
|
|
34594
|
+
for (const popupElement of popupsMountingContentForOpen) {
|
|
34595
|
+
if (popupElement !== element && popupElement.contains(element)) {
|
|
34596
|
+
return popupElement;
|
|
34597
|
+
}
|
|
34598
|
+
}
|
|
34599
|
+
return null;
|
|
34600
|
+
};
|
|
34568
34601
|
|
|
34569
34602
|
// requestIdleCallback is missing from Safari; a timeout is close enough there.
|
|
34570
34603
|
const requestIdle = (callback) =>
|
|
@@ -34734,6 +34767,9 @@ const useDisplayedLayoutEffect = (ref, callback, deps) => {
|
|
|
34734
34767
|
// Set by the mount effect below for an element that lives in its openable
|
|
34735
34768
|
// ancestor's façade rather than in what that ancestor opens.
|
|
34736
34769
|
const displayedWhileAncestorClosedRef = useRef(false);
|
|
34770
|
+
// The popup whose opening will answer what the mount could not — see the
|
|
34771
|
+
// mount effect below.
|
|
34772
|
+
const decisionDeferredToRef = useRef(null);
|
|
34737
34773
|
|
|
34738
34774
|
// Run on mount (or when deps change) — but only if the element is visible.
|
|
34739
34775
|
useLayoutEffect(() => {
|
|
@@ -34747,14 +34783,26 @@ const useDisplayedLayoutEffect = (ref, callback, deps) => {
|
|
|
34747
34783
|
return;
|
|
34748
34784
|
}
|
|
34749
34785
|
if (!isAncestorOpen(ancestor)) {
|
|
34750
|
-
if (
|
|
34786
|
+
if (isMountingContentForOpen(ancestor)) {
|
|
34751
34787
|
// The popup building its content for its own opening: nothing in it
|
|
34752
34788
|
// is on screen, and the open about to follow reveals all of it. Known
|
|
34753
34789
|
// without asking the layout, which a synchronous mount would have to
|
|
34754
|
-
// bring up to date once per element asking
|
|
34755
|
-
|
|
34756
|
-
|
|
34757
|
-
|
|
34790
|
+
// bring up to date once per element asking; the observer below fires
|
|
34791
|
+
// once it opens.
|
|
34792
|
+
return;
|
|
34793
|
+
}
|
|
34794
|
+
const popupMounting = findPopupMountingContentAround(el);
|
|
34795
|
+
if (popupMounting) {
|
|
34796
|
+
// Under a closed trigger — a picker's façade, an expandable's header —
|
|
34797
|
+
// inside a popup being built. Whether this element is on screen once
|
|
34798
|
+
// that popup is open is exactly what the layout cannot say while the
|
|
34799
|
+
// popup, and everything in it, is display:none: it would answer "hidden"
|
|
34800
|
+
// for a façade that the opening is about to show. Asked again when the
|
|
34801
|
+
// popup opens (see the observer effect below).
|
|
34802
|
+
decisionDeferredToRef.current = popupMounting;
|
|
34803
|
+
return;
|
|
34804
|
+
}
|
|
34805
|
+
if (!isDisplayedDespiteClosedAncestor(el, ancestor)) {
|
|
34758
34806
|
// Ancestor is closed and took this element off screen with it — skip
|
|
34759
34807
|
// now; the observeAncestorOpenState call below will fire once it
|
|
34760
34808
|
// opens.
|
|
@@ -34778,19 +34826,63 @@ const useDisplayedLayoutEffect = (ref, callback, deps) => {
|
|
|
34778
34826
|
if (!ancestor) {
|
|
34779
34827
|
return undefined;
|
|
34780
34828
|
}
|
|
34781
|
-
|
|
34782
|
-
|
|
34783
|
-
|
|
34784
|
-
|
|
34785
|
-
|
|
34786
|
-
|
|
34787
|
-
|
|
34788
|
-
|
|
34789
|
-
|
|
34790
|
-
|
|
34791
|
-
|
|
34792
|
-
|
|
34793
|
-
|
|
34829
|
+
const stopObservingAncestor = observeAncestorOpenState(
|
|
34830
|
+
ancestor,
|
|
34831
|
+
({ isOpen }) => {
|
|
34832
|
+
if (!isOpen) {
|
|
34833
|
+
return;
|
|
34834
|
+
}
|
|
34835
|
+
if (displayedWhileAncestorClosedRef.current) {
|
|
34836
|
+
// Façade content: on screen the whole time, so this opening reveals
|
|
34837
|
+
// nothing here — and `becauseAncestorOpened: true` about it would be
|
|
34838
|
+
// false in a way consumers act on (see use_auto_focus.js).
|
|
34839
|
+
return;
|
|
34840
|
+
}
|
|
34841
|
+
const lastEl = ref.current;
|
|
34842
|
+
callbackRef.current(lastEl, createDisplayedEvent(ancestor, true));
|
|
34843
|
+
},
|
|
34844
|
+
);
|
|
34845
|
+
const popupMounting = decisionDeferredToRef.current;
|
|
34846
|
+
if (!popupMounting) {
|
|
34847
|
+
return stopObservingAncestor;
|
|
34848
|
+
}
|
|
34849
|
+
// The mount deferred its decision to this popup's opening (see above):
|
|
34850
|
+
// once it is open, the layout answers for what the closed ancestor keeps
|
|
34851
|
+
// on screen. A façade element is then displayed, by that opening — which
|
|
34852
|
+
// owns it, the way it owns everything the popup reveals. An element the
|
|
34853
|
+
// closed ancestor genuinely hides stays with the observer above.
|
|
34854
|
+
const stopObservingPopup = observeAncestorOpenState(
|
|
34855
|
+
popupMounting,
|
|
34856
|
+
({ isOpen }) => {
|
|
34857
|
+
if (!isOpen) {
|
|
34858
|
+
return;
|
|
34859
|
+
}
|
|
34860
|
+
stopObservingPopup();
|
|
34861
|
+
decisionDeferredToRef.current = null;
|
|
34862
|
+
const lastEl = ref.current;
|
|
34863
|
+
if (!lastEl) {
|
|
34864
|
+
return;
|
|
34865
|
+
}
|
|
34866
|
+
if (isAncestorOpen(ancestor)) {
|
|
34867
|
+
callbackRef.current(
|
|
34868
|
+
lastEl,
|
|
34869
|
+
createDisplayedEvent(popupMounting, true),
|
|
34870
|
+
);
|
|
34871
|
+
return;
|
|
34872
|
+
}
|
|
34873
|
+
if (isDisplayedDespiteClosedAncestor(lastEl, ancestor)) {
|
|
34874
|
+
displayedWhileAncestorClosedRef.current = true;
|
|
34875
|
+
callbackRef.current(
|
|
34876
|
+
lastEl,
|
|
34877
|
+
createDisplayedEvent(popupMounting, true),
|
|
34878
|
+
);
|
|
34879
|
+
}
|
|
34880
|
+
},
|
|
34881
|
+
);
|
|
34882
|
+
return () => {
|
|
34883
|
+
stopObservingAncestor();
|
|
34884
|
+
stopObservingPopup();
|
|
34885
|
+
};
|
|
34794
34886
|
}, []);
|
|
34795
34887
|
};
|
|
34796
34888
|
|
|
@@ -68803,6 +68895,7 @@ const ListItems = ({
|
|
|
68803
68895
|
const virtual = useContext(ListVirtualContext);
|
|
68804
68896
|
const slotId = useContext(ListSlotContext);
|
|
68805
68897
|
const renderWindow = useContext(RenderWindowContext);
|
|
68898
|
+
const separator = useContext(SeparatorContext);
|
|
68806
68899
|
// The vnode drawn for a row, kept by item: a run rendering again (its window
|
|
68807
68900
|
// moving, its first paint's budget giving way to the full one) hands preact
|
|
68808
68901
|
// the same vnode for a row that has not changed, and preact leaves that
|
|
@@ -68811,14 +68904,14 @@ const ListItems = ({
|
|
|
68811
68904
|
// row at the same index, in the same refreshing state: everything the
|
|
68812
68905
|
// function is given.
|
|
68813
68906
|
const rowVnodesRef = useRef(null);
|
|
68814
|
-
if (!rowVnodesRef.current || rowVnodesRef.current.renderItem !== renderItem) {
|
|
68907
|
+
if (!rowVnodesRef.current || rowVnodesRef.current.renderItem !== renderItem || rowVnodesRef.current.separator !== separator) {
|
|
68815
68908
|
rowVnodesRef.current = {
|
|
68816
68909
|
renderItem,
|
|
68910
|
+
separator,
|
|
68817
68911
|
byItem: new Map()
|
|
68818
68912
|
};
|
|
68819
68913
|
}
|
|
68820
68914
|
const rowVnodesByItem = rowVnodesRef.current.byItem;
|
|
68821
|
-
const separator = useContext(SeparatorContext);
|
|
68822
68915
|
const store = useItemStore({
|
|
68823
68916
|
items,
|
|
68824
68917
|
count,
|
|
@@ -69048,17 +69141,33 @@ const ListItems = ({
|
|
|
69048
69141
|
const item = getItemAt(rowIndex);
|
|
69049
69142
|
const key = item === undefined ? `${ownerId}_skeleton_${rowIndex}` : idOf(item, rowIndex);
|
|
69050
69143
|
let rowVnode;
|
|
69144
|
+
let rowContextValue;
|
|
69145
|
+
let rowKept = null;
|
|
69051
69146
|
if (item !== undefined) {
|
|
69052
69147
|
const rowVnodeKept = rowVnodesByItem.get(item);
|
|
69053
69148
|
if (rowVnodeKept && rowVnodeKept.rowIndex === rowIndex && rowVnodeKept.refreshing === renderItemState.refreshing) {
|
|
69054
69149
|
rowVnode = rowVnodeKept.vnode;
|
|
69150
|
+
rowContextValue = rowVnodeKept.rowContextValue;
|
|
69151
|
+
rowKept = rowVnodeKept;
|
|
69055
69152
|
} else {
|
|
69056
69153
|
rowVnode = renderItem(item, rowIndex, renderItemState);
|
|
69057
|
-
|
|
69154
|
+
// Kept with the vnode, for the same reason: a context value that is a
|
|
69155
|
+
// fresh object on every render forces every consumer of it to render,
|
|
69156
|
+
// which is the row's own chain — the vnode handed back unchanged would
|
|
69157
|
+
// then buy nothing.
|
|
69158
|
+
rowContextValue = {
|
|
69159
|
+
id: key,
|
|
69160
|
+
index: rowIndex,
|
|
69161
|
+
item
|
|
69162
|
+
};
|
|
69163
|
+
rowKept = {
|
|
69058
69164
|
vnode: rowVnode,
|
|
69165
|
+
rowContextValue,
|
|
69059
69166
|
rowIndex,
|
|
69060
|
-
refreshing: renderItemState.refreshing
|
|
69061
|
-
|
|
69167
|
+
refreshing: renderItemState.refreshing,
|
|
69168
|
+
separatorVnode: null
|
|
69169
|
+
};
|
|
69170
|
+
rowVnodesByItem.set(item, rowKept);
|
|
69062
69171
|
}
|
|
69063
69172
|
} else if (renderRowSkeleton === false) {
|
|
69064
69173
|
// The row must still take its room: without it the rows below would
|
|
@@ -69082,20 +69191,25 @@ const ListItems = ({
|
|
|
69082
69191
|
// as a hairline under the label.
|
|
69083
69192
|
const drawSeparator = separator && rowIndex > 0 && !opensGroup(groupKeyOf(item, rowIndex));
|
|
69084
69193
|
if (drawSeparator) {
|
|
69085
|
-
|
|
69086
|
-
|
|
69087
|
-
|
|
69194
|
+
// Kept with the row too: a separator built again is a separator
|
|
69195
|
+
// rendered again.
|
|
69196
|
+
let separatorVnode = rowKept ? rowKept.separatorVnode : null;
|
|
69197
|
+
if (!separatorVnode) {
|
|
69198
|
+
separatorVnode = cloneElement(resolveSeparatorVnode(separator, rowIndex - 1), {
|
|
69199
|
+
key: `${key}_separator`
|
|
69200
|
+
});
|
|
69201
|
+
if (rowKept) {
|
|
69202
|
+
rowKept.separatorVnode = separatorVnode;
|
|
69203
|
+
}
|
|
69204
|
+
}
|
|
69205
|
+
pushRow(separatorVnode, item, rowIndex);
|
|
69088
69206
|
}
|
|
69089
69207
|
pushRow(jsx(ListRowContext.Provider, {
|
|
69090
69208
|
value: item === undefined ? {
|
|
69091
69209
|
id: key,
|
|
69092
69210
|
index: rowIndex,
|
|
69093
69211
|
...getSkeletonRow()
|
|
69094
|
-
} :
|
|
69095
|
-
id: key,
|
|
69096
|
-
index: rowIndex,
|
|
69097
|
-
item
|
|
69098
|
-
},
|
|
69212
|
+
} : rowContextValue,
|
|
69099
69213
|
children: rowVnode
|
|
69100
69214
|
}, key), item, rowIndex);
|
|
69101
69215
|
}
|