@jsenv/navi 0.29.365 → 0.29.366
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 +50 -6
- package/dist/dev/jsenv_navi.js.map +4 -4
- package/dist/jsenv_navi.js +8 -6
- package/dist/jsenv_navi.js.map +4 -4
- package/docs/popup_lift.md +9 -0
- package/docs/popup_open.md +15 -2
- package/package.json +1 -1
package/dist/dev/jsenv_navi.js
CHANGED
|
@@ -28872,6 +28872,8 @@ const visitedUrlsSignal = browserIntegration.visitedUrlsSignal;
|
|
|
28872
28872
|
browserIntegration.handleActionTask;
|
|
28873
28873
|
|
|
28874
28874
|
const idUsageMap = new Map();
|
|
28875
|
+
// Keys found in the entry with nobody to claim them, already reported.
|
|
28876
|
+
const orphanKeysReported = new Set();
|
|
28875
28877
|
const useNavStateWithWarnings = (id, options) => {
|
|
28876
28878
|
const idRef = useRef(undefined);
|
|
28877
28879
|
if (idRef.current !== id) {
|
|
@@ -28895,6 +28897,15 @@ Consider using unique IDs for each component instance.`,
|
|
|
28895
28897
|
}
|
|
28896
28898
|
|
|
28897
28899
|
useEffect(() => {
|
|
28900
|
+
// Registered here as well as in the render above: preact/compat's
|
|
28901
|
+
// Suspense parks a subtree by running every hook cleanup in it, and the
|
|
28902
|
+
// render resuming it carries the same id.
|
|
28903
|
+
if (!idUsageMap.has(id)) {
|
|
28904
|
+
idUsageMap.set(id, {
|
|
28905
|
+
stackTrace: new Error().stack,
|
|
28906
|
+
});
|
|
28907
|
+
}
|
|
28908
|
+
warnAboutOrphanGeneratedKeys();
|
|
28898
28909
|
return () => {
|
|
28899
28910
|
idUsageMap.delete(id);
|
|
28900
28911
|
};
|
|
@@ -28903,6 +28914,31 @@ Consider using unique IDs for each component instance.`,
|
|
|
28903
28914
|
return useNavStateBasic(id, options);
|
|
28904
28915
|
};
|
|
28905
28916
|
|
|
28917
|
+
// A generated id (preact's useId()) names one mount. State written under one
|
|
28918
|
+
// outlives that mount in the history entry — a page left with a popup open —
|
|
28919
|
+
// and the mount coming back to the entry generates another id: the state is
|
|
28920
|
+
// there, and nothing reads it. Reported when a component mounting on the entry
|
|
28921
|
+
// finds such a key, the moment someone expected the state back.
|
|
28922
|
+
const warnAboutOrphanGeneratedKeys = () => {
|
|
28923
|
+
const state = browserIntegration.getDocumentState();
|
|
28924
|
+
if (!state) {
|
|
28925
|
+
return;
|
|
28926
|
+
}
|
|
28927
|
+
for (const key of Object.keys(state)) {
|
|
28928
|
+
if (
|
|
28929
|
+
!isLikelyPreactGeneratedId(key) ||
|
|
28930
|
+
idUsageMap.has(key) ||
|
|
28931
|
+
orphanKeysReported.has(key)
|
|
28932
|
+
) {
|
|
28933
|
+
continue;
|
|
28934
|
+
}
|
|
28935
|
+
orphanKeysReported.add(key);
|
|
28936
|
+
console.warn(
|
|
28937
|
+
`useNavState: this history entry holds "${key}", written by a component whose id was generated (preact's useId()) and that is not mounted anymore — a Picker without an id, a popup with navState and no id. A generated id names one mount, so nothing will read that state again: a popup open when this screen was left comes back closed. Give the component a stable id if it was meant to be found as it was.`,
|
|
28938
|
+
);
|
|
28939
|
+
}
|
|
28940
|
+
};
|
|
28941
|
+
|
|
28906
28942
|
const NO_OP = () => {};
|
|
28907
28943
|
const NO_ID_GIVEN = [undefined, NO_OP, NO_OP];
|
|
28908
28944
|
// What the computed below answers for a key the document state does not hold:
|
|
@@ -65393,8 +65429,8 @@ const PickerCustom = props => {
|
|
|
65393
65429
|
// before computing popupId below, so two Pickers without an explicit id never collide.
|
|
65394
65430
|
// Captured before the fallback chain below overwrites props.id — needed to
|
|
65395
65431
|
// know whether the id actually came from the caller (stable) or from
|
|
65396
|
-
// useId()/ControlIdContext (
|
|
65397
|
-
// pickerNavType below.
|
|
65432
|
+
// useId()/ControlIdContext (a generated id names one mount: a reload, or a
|
|
65433
|
+
// return to this page, generates another), see pickerNavType below.
|
|
65398
65434
|
const hasExplicitId = Boolean(props.id);
|
|
65399
65435
|
const idDefault = useId();
|
|
65400
65436
|
const controlId = useContext(ControlIdContext);
|
|
@@ -65471,10 +65507,12 @@ const PickerCustom = props => {
|
|
|
65471
65507
|
// pushes a history entry so the back button closes it. Every other case
|
|
65472
65508
|
// (popover mode, or a dialog whose id was auto-generated via useId()/
|
|
65473
65509
|
// ControlIdContext) replaces the current history state instead — a
|
|
65474
|
-
// generated id
|
|
65475
|
-
//
|
|
65476
|
-
//
|
|
65477
|
-
//
|
|
65510
|
+
// generated id names one mount, so pushing it would either leave an entry
|
|
65511
|
+
// nothing reads or, worse, collide with a different component's own
|
|
65512
|
+
// generated id (see useNavState's own fallback for the same concern,
|
|
65513
|
+
// applied here proactively for the id we control). What a generated id
|
|
65514
|
+
// costs either way: the state is written, and the mount coming back to
|
|
65515
|
+
// the page (or a reload) finds it under a key it does not have.
|
|
65478
65516
|
const pickerNavType = mode === "dialog" && hasExplicitId ? "push" : "replace";
|
|
65479
65517
|
const [expanded, enterExpanded, leaveExpanded] = useNavState(popupId, {
|
|
65480
65518
|
type: pickerNavType,
|
|
@@ -75743,6 +75781,12 @@ const PickerFirstResolver = props => {
|
|
|
75743
75781
|
* content failed to load, its value could not be resolved…). Shown as a
|
|
75744
75782
|
* callout on the trigger, open or closed — the caller has nothing to place.
|
|
75745
75783
|
* Dismissing it discards that error; a new `error` value raises another one.
|
|
75784
|
+
* @param {string} [id] What the popup's open state is kept under in the
|
|
75785
|
+
* history entry: a screen left and come back to finds the picker open, and
|
|
75786
|
+
* in dialog mode the opening is an entry of its own, closed by the back
|
|
75787
|
+
* button before the screen is left. Left out, the key is a generated id,
|
|
75788
|
+
* which names one mount: the state survives neither leaving the screen nor a
|
|
75789
|
+
* reload. A picker whose popup leads somewhere (a link inside it) has one.
|
|
75746
75790
|
* @param {"popover"|"dialog"|"callout"} [mode] Which popup the children open
|
|
75747
75791
|
* in. Left out, a popover on a large screen and a dialog on a narrow one.
|
|
75748
75792
|
* `"callout"` shows them in the picker's own callout — the speech bubble its
|