@jsenv/navi 0.30.15 → 0.30.16
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 +218 -133
- package/dist/dev/jsenv_navi.js.map +11 -11
- package/dist/jsenv_navi.js +218 -133
- package/dist/jsenv_navi.js.map +11 -11
- package/docs/popup_open.md +39 -29
- package/docs/route_transitions.md +6 -4
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -14034,12 +14034,18 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
14034
14034
|
url !== readAddress()
|
|
14035
14035
|
) {
|
|
14036
14036
|
const delta = adjacentEntryDelta(url);
|
|
14037
|
-
if (delta
|
|
14038
|
-
|
|
14039
|
-
|
|
14040
|
-
|
|
14041
|
-
|
|
14042
|
-
|
|
14037
|
+
if (delta !== 0) {
|
|
14038
|
+
// The press is still the press: what it asks of a route transition is
|
|
14039
|
+
// about this crossing, and the traversal is announced with it.
|
|
14040
|
+
elidedPressPending = {
|
|
14041
|
+
element: options.element,
|
|
14042
|
+
routeTransition: options.routeTransition,
|
|
14043
|
+
};
|
|
14044
|
+
if (delta === -1) {
|
|
14045
|
+
window.history.back();
|
|
14046
|
+
} else {
|
|
14047
|
+
window.history.forward();
|
|
14048
|
+
}
|
|
14043
14049
|
return undefined;
|
|
14044
14050
|
}
|
|
14045
14051
|
}
|
|
@@ -14427,6 +14433,8 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
14427
14433
|
const state = popstateEvent.state;
|
|
14428
14434
|
const landOn = landOnPending;
|
|
14429
14435
|
landOnPending = null;
|
|
14436
|
+
const elidedPress = elidedPressPending;
|
|
14437
|
+
elidedPressPending = null;
|
|
14430
14438
|
if (landOn) {
|
|
14431
14439
|
handleRoutingTask(landOn.url, {
|
|
14432
14440
|
reason: `"popstate" event for ${url}, landing on ${landOn.url}`,
|
|
@@ -14440,6 +14448,7 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
14440
14448
|
reason: `"popstate" event for ${url}`,
|
|
14441
14449
|
navigationType: "traverse",
|
|
14442
14450
|
state,
|
|
14451
|
+
...elidedPress,
|
|
14443
14452
|
});
|
|
14444
14453
|
});
|
|
14445
14454
|
|
|
@@ -14507,6 +14516,10 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
14507
14516
|
// asked for it (see navBack's `landOn`). Read by the popstate listener,
|
|
14508
14517
|
// which is the one place the landing is applied.
|
|
14509
14518
|
let landOnPending = null;
|
|
14519
|
+
// The press a push to the entry next door was made by, when it was taken as
|
|
14520
|
+
// a traversal (see handleRoutingTask): announced with the "popstate" that
|
|
14521
|
+
// answers it, which has no press of its own.
|
|
14522
|
+
let elidedPressPending = null;
|
|
14510
14523
|
// The back navBack asked for, from history.back() to the "popstate" that
|
|
14511
14524
|
// answers it. Meanwhile the document still reads the entry being left (see
|
|
14512
14525
|
// whenBackLanded).
|
|
@@ -16342,11 +16355,12 @@ PSEUDO_CLASSES[":-navi-has-value"] = {
|
|
|
16342
16355
|
};
|
|
16343
16356
|
{
|
|
16344
16357
|
// How long a press stays drawn, at least, from the frame that first painted
|
|
16345
|
-
// it
|
|
16346
|
-
//
|
|
16347
|
-
//
|
|
16348
|
-
// is
|
|
16349
|
-
|
|
16358
|
+
// it. An ordinary tap lasts 30 to 80ms, and its pointerup can be handled
|
|
16359
|
+
// right after its pointerdown when the main thread was busy: released at
|
|
16360
|
+
// once, a press shows on 0 to 3 frames, which is no press at all to the eye.
|
|
16361
|
+
// 140ms is the Button's shrink (button_ui.jsx): 100ms down, then 40ms at
|
|
16362
|
+
// the bottom before it goes back up, whatever the length of the tap.
|
|
16363
|
+
const PRESS_SHOWN_AT_LEAST = 140;
|
|
16350
16364
|
// element → the press going on there, until the element stops being drawn
|
|
16351
16365
|
// pressed. Keyed by the element, not held by its tracker: Box re-runs its
|
|
16352
16366
|
// tracking whenever the element's state changes, which is what pressing it
|
|
@@ -26879,7 +26893,9 @@ const arraySignalStore = (
|
|
|
26879
26893
|
name,
|
|
26880
26894
|
};
|
|
26881
26895
|
|
|
26882
|
-
|
|
26896
|
+
// `answer`: the props come from an answer, see upsertAnswer. createItem
|
|
26897
|
+
// hands it to the relations, which write the children inside the props.
|
|
26898
|
+
const createItemFromProps = (props, answer) => {
|
|
26883
26899
|
if (props === null || typeof props !== "object") {
|
|
26884
26900
|
return props;
|
|
26885
26901
|
}
|
|
@@ -26891,7 +26907,7 @@ const arraySignalStore = (
|
|
|
26891
26907
|
`${name || "store"}: an item arrived without "${idKey}" (it has ${Object.keys(props).join(", ")}) — declare its key with idKey, or give a single item an id of its own ({ id: "me", … })`,
|
|
26892
26908
|
);
|
|
26893
26909
|
}
|
|
26894
|
-
const item = createItem(props);
|
|
26910
|
+
const item = createItem(props, answer);
|
|
26895
26911
|
return item;
|
|
26896
26912
|
};
|
|
26897
26913
|
|
|
@@ -27117,7 +27133,12 @@ ${[idKey, ...uniqueKeys].join(", ")}`,
|
|
|
27117
27133
|
const valueChangedByWrite = (newValue, oldValue) => newValue !== oldValue;
|
|
27118
27134
|
const valueChangedByAnswer = (newValue, oldValue) =>
|
|
27119
27135
|
newValue !== oldValue && !compareTwoJsValues(newValue, oldValue);
|
|
27120
|
-
|
|
27136
|
+
// One write, however many stores its relations reach: an effect reading the
|
|
27137
|
+
// rows (a render, the page kept for the next document) runs once the whole
|
|
27138
|
+
// write is in, rather than once per child written, half of it still to come.
|
|
27139
|
+
const upsertWith = (args, answer) => batch(() => upsertWithNow(args, answer));
|
|
27140
|
+
const upsertWithNow = (args, answer) => {
|
|
27141
|
+
const valueChanged = answer ? valueChangedByAnswer : valueChangedByWrite;
|
|
27121
27142
|
const mutationsMap = new Map(); // Map<itemId, propertyMutations>
|
|
27122
27143
|
const triggerPropertyMutations = () => {
|
|
27123
27144
|
for (const itemPropertiesObserver of itemPropertiesObserverSet) {
|
|
@@ -27186,11 +27207,12 @@ ${[idKey, ...uniqueKeys].join(", ")}`,
|
|
|
27186
27207
|
// A relation (.one(), .many() and their scoped forms in
|
|
27187
27208
|
// resource_graph.js): the row holds which children it points to,
|
|
27188
27209
|
// the children live in their own store, and whoever reads them
|
|
27189
|
-
// follows them there. Its setter writes them
|
|
27190
|
-
//
|
|
27191
|
-
//
|
|
27192
|
-
//
|
|
27193
|
-
|
|
27210
|
+
// follows them there. Its setter writes them, compared as this
|
|
27211
|
+
// write compares (`answer`), and says whether the row points
|
|
27212
|
+
// elsewhere now. Compared as a value instead, the children
|
|
27213
|
+
// received are never the object the row hands out, and every
|
|
27214
|
+
// write naming the relation would replace the row.
|
|
27215
|
+
if (set.call(itemWithProps, newValue, answer)) {
|
|
27194
27216
|
hasChanges = true;
|
|
27195
27217
|
propertyMutations[key] = {
|
|
27196
27218
|
oldValue,
|
|
@@ -27238,7 +27260,7 @@ ${[idKey, ...uniqueKeys].join(", ")}`,
|
|
|
27238
27260
|
if (array.length === 0) {
|
|
27239
27261
|
const arrayAllCreated = [];
|
|
27240
27262
|
for (const props of propsArray) {
|
|
27241
|
-
const item = createItemFromProps(props);
|
|
27263
|
+
const item = createItemFromProps(props, answer);
|
|
27242
27264
|
arrayAllCreated.push(item);
|
|
27243
27265
|
}
|
|
27244
27266
|
arraySignal.value = arrayAllCreated;
|
|
@@ -27275,7 +27297,7 @@ ${[idKey, ...uniqueKeys].join(", ")}`,
|
|
|
27275
27297
|
arrayWithOnlyAffectedItems.push(itemWithPropsOrItem);
|
|
27276
27298
|
} else {
|
|
27277
27299
|
hasNew = true;
|
|
27278
|
-
const item = createItemFromProps(props);
|
|
27300
|
+
const item = createItemFromProps(props, answer);
|
|
27279
27301
|
arraySomeUpdated.push(item);
|
|
27280
27302
|
arrayWithOnlyAffectedItems.push(item);
|
|
27281
27303
|
}
|
|
@@ -27347,23 +27369,24 @@ ${[idKey, ...uniqueKeys].join(", ")}`,
|
|
|
27347
27369
|
triggerPropertyMutations();
|
|
27348
27370
|
return updatedItem;
|
|
27349
27371
|
}
|
|
27350
|
-
const item = createItemFromProps(props);
|
|
27372
|
+
const item = createItemFromProps(props, answer);
|
|
27351
27373
|
arraySomeUpdated.push(item);
|
|
27352
27374
|
arraySignal.value = arraySomeUpdated;
|
|
27353
27375
|
triggerPropertyMutations();
|
|
27354
27376
|
return item;
|
|
27355
27377
|
};
|
|
27356
|
-
const upsert = (...args) => upsertWith(args,
|
|
27378
|
+
const upsert = (...args) => upsertWith(args, false);
|
|
27357
27379
|
/**
|
|
27358
27380
|
* Writes what the server sent — a callback's answer, a pushed message (a
|
|
27359
27381
|
* websocket's, a server-sent event's) — into the store. Takes what `upsert`
|
|
27360
27382
|
* takes and returns the same: a row equal in depth to the one held stays
|
|
27361
27383
|
* the one held, and its readers stay still, where `upsert` compares by
|
|
27362
|
-
* reference and JSON makes every nested object a new one.
|
|
27384
|
+
* reference and JSON makes every nested object a new one. The children its
|
|
27385
|
+
* relations carry into their own stores are compared the same way. A new row joins no
|
|
27363
27386
|
* `GET_MANY` and no `GET_RANGE` composition: read again what it belongs to
|
|
27364
27387
|
* (docs/resource.md).
|
|
27365
27388
|
*/
|
|
27366
|
-
const upsertAnswer = (...args) => upsertWith(args,
|
|
27389
|
+
const upsertAnswer = (...args) => upsertWith(args, true);
|
|
27367
27390
|
const drop = (...args) => {
|
|
27368
27391
|
const removedItemArray = [];
|
|
27369
27392
|
const triggerRemovedMutations = () => {
|
|
@@ -29159,7 +29182,7 @@ const resource = (name, restCallbacks = {}) => {
|
|
|
29159
29182
|
const store = arraySignalStore([], idKey, {
|
|
29160
29183
|
uniqueKeys,
|
|
29161
29184
|
name: `${name} store`,
|
|
29162
|
-
createItem: (props) => {
|
|
29185
|
+
createItem: (props, answer) => {
|
|
29163
29186
|
const item = Object.create(itemPrototype);
|
|
29164
29187
|
Object.assign(item, props);
|
|
29165
29188
|
Object.defineProperty(item, SYMBOL_IDENTITY, {
|
|
@@ -29169,7 +29192,7 @@ const resource = (name, restCallbacks = {}) => {
|
|
|
29169
29192
|
configurable: false,
|
|
29170
29193
|
});
|
|
29171
29194
|
for (const setupCallback of setupCallbackSet) {
|
|
29172
|
-
setupCallback(item);
|
|
29195
|
+
setupCallback(item, answer);
|
|
29173
29196
|
}
|
|
29174
29197
|
return item;
|
|
29175
29198
|
},
|
|
@@ -29499,9 +29522,9 @@ const createResource = (
|
|
|
29499
29522
|
const childName = `${name}.${propertyName}`;
|
|
29500
29523
|
const childIdKey = childResource.idKey;
|
|
29501
29524
|
const childStore = childResource.store;
|
|
29502
|
-
addItemSetup((item) => {
|
|
29525
|
+
addItemSetup((item, answer) => {
|
|
29503
29526
|
const childItemIdSignal = signal();
|
|
29504
|
-
const updateChildItemId = (value) => {
|
|
29527
|
+
const updateChildItemId = (value, answer) => {
|
|
29505
29528
|
const currentChildItemId = childItemIdSignal.peek();
|
|
29506
29529
|
let childItemProps;
|
|
29507
29530
|
if (isProps(value)) {
|
|
@@ -29515,7 +29538,9 @@ const createResource = (
|
|
|
29515
29538
|
childItemIdSignal.value = undefined;
|
|
29516
29539
|
return true;
|
|
29517
29540
|
}
|
|
29518
|
-
const childItem =
|
|
29541
|
+
const childItem = answer
|
|
29542
|
+
? childStore.upsertAnswer(childItemProps)
|
|
29543
|
+
: childStore.upsert(childItemProps);
|
|
29519
29544
|
const childItemId = childItem[childIdKey];
|
|
29520
29545
|
if (currentChildItemId === childItemId) {
|
|
29521
29546
|
return false;
|
|
@@ -29523,7 +29548,7 @@ const createResource = (
|
|
|
29523
29548
|
childItemIdSignal.value = childItemId;
|
|
29524
29549
|
return true;
|
|
29525
29550
|
};
|
|
29526
|
-
updateChildItemId(item[propertyName]);
|
|
29551
|
+
updateChildItemId(item[propertyName], answer);
|
|
29527
29552
|
const childItemSignal = computed(() =>
|
|
29528
29553
|
childStore.select(childItemIdSignal.value),
|
|
29529
29554
|
);
|
|
@@ -29708,14 +29733,14 @@ Return the child alone, and "${propertyName}" embedded in what the "${name}" cal
|
|
|
29708
29733
|
${name}.many("${propertyName}") source location: ${declarationSite}`,
|
|
29709
29734
|
);
|
|
29710
29735
|
};
|
|
29711
|
-
addItemSetup((item) => {
|
|
29736
|
+
addItemSetup((item, answer) => {
|
|
29712
29737
|
const childItemIdArraySignal = signal([]);
|
|
29713
29738
|
const updateChildItemIdArray = createChildIdArrayUpdater(
|
|
29714
29739
|
childStore,
|
|
29715
29740
|
childIdKey,
|
|
29716
29741
|
childItemIdArraySignal,
|
|
29717
29742
|
);
|
|
29718
|
-
updateChildItemIdArray(item[propertyName]);
|
|
29743
|
+
updateChildItemIdArray(item[propertyName], answer);
|
|
29719
29744
|
const childItemArraySignal = computed(() => {
|
|
29720
29745
|
const idArray = childItemIdArraySignal.value;
|
|
29721
29746
|
const arr = childStore.selectAll(idArray);
|
|
@@ -30051,7 +30076,7 @@ ${name}.many("${propertyName}") source location: ${declarationSite}`,
|
|
|
30051
30076
|
const childSetupCallbackSet = new Set();
|
|
30052
30077
|
const childAddItemSetup = (callback) => childSetupCallbackSet.add(callback);
|
|
30053
30078
|
const applyPropsMap = new Map(); // ownerId → applyProps(props | null)
|
|
30054
|
-
addItemSetup((ownerItem) => {
|
|
30079
|
+
addItemSetup((ownerItem, answer) => {
|
|
30055
30080
|
const ownerId = ownerItem[idKey];
|
|
30056
30081
|
// A stable child object, mutated in place: reactive getters/setters from
|
|
30057
30082
|
// chained .one() etc. are defined on it once and survive prop updates.
|
|
@@ -30069,8 +30094,10 @@ ${name}.many("${propertyName}") source location: ${declarationSite}`,
|
|
|
30069
30094
|
// relation, `owner[propertyName] = …` — whoever reads the child sees it.
|
|
30070
30095
|
const childVersionSignal = signal(0);
|
|
30071
30096
|
// Returns whether the child changed — what the store asks a relation
|
|
30072
|
-
// (see assign in array_signal_store.js).
|
|
30073
|
-
|
|
30097
|
+
// (see assign in array_signal_store.js). `answer`: the props come from
|
|
30098
|
+
// an answer, and a value equal in depth to the one held is no change
|
|
30099
|
+
// (see upsertAnswer).
|
|
30100
|
+
const applyProps = (props, answer) => {
|
|
30074
30101
|
if (props === undefined) {
|
|
30075
30102
|
return false;
|
|
30076
30103
|
}
|
|
@@ -30087,13 +30114,20 @@ ${name}.many("${propertyName}") source location: ${declarationSite}`,
|
|
|
30087
30114
|
for (const [key, value] of Object.entries(props)) {
|
|
30088
30115
|
const descriptor = Object.getOwnPropertyDescriptor(childItem, key);
|
|
30089
30116
|
if (descriptor && descriptor.set) {
|
|
30090
|
-
if (descriptor.set.call(childItem, value)) {
|
|
30117
|
+
if (descriptor.set.call(childItem, value, answer)) {
|
|
30091
30118
|
changed = true;
|
|
30092
30119
|
}
|
|
30093
|
-
|
|
30094
|
-
childItem[key] = value;
|
|
30095
|
-
changed = true;
|
|
30120
|
+
continue;
|
|
30096
30121
|
}
|
|
30122
|
+
const held = childItem[key];
|
|
30123
|
+
if (held === value) {
|
|
30124
|
+
continue;
|
|
30125
|
+
}
|
|
30126
|
+
if (answer && compareTwoJsValues(held, value)) {
|
|
30127
|
+
continue;
|
|
30128
|
+
}
|
|
30129
|
+
childItem[key] = value;
|
|
30130
|
+
changed = true;
|
|
30097
30131
|
}
|
|
30098
30132
|
if (childSignal.peek() !== childItem) {
|
|
30099
30133
|
childSignal.value = childItem; // first activation
|
|
@@ -30111,7 +30145,7 @@ ${name}.many("${propertyName}") source location: ${declarationSite}`,
|
|
|
30111
30145
|
applyPropsMap.set(ownerId, applyProps);
|
|
30112
30146
|
}
|
|
30113
30147
|
|
|
30114
|
-
applyProps(ownerItem[propertyName]);
|
|
30148
|
+
applyProps(ownerItem[propertyName], answer);
|
|
30115
30149
|
|
|
30116
30150
|
Object.defineProperty(ownerItem, propertyName, {
|
|
30117
30151
|
get: () => {
|
|
@@ -30154,7 +30188,7 @@ ${name}.many("${propertyName}") source location: ${declarationSite}`,
|
|
|
30154
30188
|
// brings its child.
|
|
30155
30189
|
const applyProps = applyPropsMap.get(ownerId);
|
|
30156
30190
|
if (applyProps) {
|
|
30157
|
-
applyProps(props);
|
|
30191
|
+
applyProps(props, true);
|
|
30158
30192
|
}
|
|
30159
30193
|
return [ownerId, props];
|
|
30160
30194
|
},
|
|
@@ -30284,18 +30318,18 @@ ${name}.many("${propertyName}") source location: ${declarationSite}`,
|
|
|
30284
30318
|
const createScope = (ownerKey) => {
|
|
30285
30319
|
const childStore = arraySignalStore([], childIdKey, {
|
|
30286
30320
|
name: `${childName}#${ownerKey} store`,
|
|
30287
|
-
createItem: (props) => {
|
|
30321
|
+
createItem: (props, answer) => {
|
|
30288
30322
|
const childItem = {};
|
|
30289
30323
|
Object.assign(childItem, props);
|
|
30290
30324
|
for (const childSetup of childSetupCallbackSet) {
|
|
30291
|
-
childSetup(childItem);
|
|
30325
|
+
childSetup(childItem, answer);
|
|
30292
30326
|
}
|
|
30293
30327
|
return childItem;
|
|
30294
30328
|
},
|
|
30295
30329
|
});
|
|
30296
30330
|
return { childStore, idArraySignal: signal([]) };
|
|
30297
30331
|
};
|
|
30298
|
-
addItemSetup((item) => {
|
|
30332
|
+
addItemSetup((item, answer) => {
|
|
30299
30333
|
const ownerId = item[idKey];
|
|
30300
30334
|
let scope;
|
|
30301
30335
|
if (ownerName) {
|
|
@@ -30342,7 +30376,7 @@ ${name}.many("${propertyName}") source location: ${declarationSite}`,
|
|
|
30342
30376
|
// untouched — children may have been fetched by uniqueKey before the
|
|
30343
30377
|
// parent was loaded. Only an explicit value replaces the collection.
|
|
30344
30378
|
if (item[propertyName] !== undefined) {
|
|
30345
|
-
updateChildItemIdArray(item[propertyName]);
|
|
30379
|
+
updateChildItemIdArray(item[propertyName], answer);
|
|
30346
30380
|
}
|
|
30347
30381
|
|
|
30348
30382
|
// When an id is renamed (PUT/PATCH changes the idKey), patch the id array.
|
|
@@ -30966,7 +31000,8 @@ ${relationLabel} source location: ${declarationSite}`,
|
|
|
30966
31000
|
// child ids, upserting each entry into the child store. The id array signal is
|
|
30967
31001
|
// only touched when the resulting ids actually differ.
|
|
30968
31002
|
// Returns whether the children the row points to changed — what the store asks
|
|
30969
|
-
// a relation (see assign in array_signal_store.js).
|
|
31003
|
+
// a relation (see assign in array_signal_store.js). `answer`: the children come
|
|
31004
|
+
// from an answer, and are written as one (see upsertAnswer).
|
|
30970
31005
|
// `wholeChildren` (.scopedMany()): each child received is the whole child, see
|
|
30971
31006
|
// toWholeScopedChild.
|
|
30972
31007
|
const createChildIdArrayUpdater = (
|
|
@@ -30975,7 +31010,7 @@ const createChildIdArrayUpdater = (
|
|
|
30975
31010
|
idArraySignal,
|
|
30976
31011
|
{ wholeChildren = false } = {},
|
|
30977
31012
|
) => {
|
|
30978
|
-
return (valueArray) => {
|
|
31013
|
+
return (valueArray, answer) => {
|
|
30979
31014
|
const currentIdArray = idArraySignal.peek();
|
|
30980
31015
|
if (!Array.isArray(valueArray)) {
|
|
30981
31016
|
if (currentIdArray.length > 0) {
|
|
@@ -30997,7 +31032,9 @@ const createChildIdArrayUpdater = (
|
|
|
30997
31032
|
} else {
|
|
30998
31033
|
continue;
|
|
30999
31034
|
}
|
|
31000
|
-
const childItem =
|
|
31035
|
+
const childItem = answer
|
|
31036
|
+
? childStore.upsertAnswer(childItemProps)
|
|
31037
|
+
: childStore.upsert(childItemProps);
|
|
31001
31038
|
const childItemId = childItem[childIdKey];
|
|
31002
31039
|
if (currentIdArray[idArray.length] !== childItemId) {
|
|
31003
31040
|
modified = true;
|
|
@@ -38785,7 +38822,8 @@ const TRANSITION_COVERED_ATTRIBUTE = "data-navi-route-transition-covered";
|
|
|
38785
38822
|
const TRANSITION_AREA_ATTRIBUTE = "data-navi-route-transition-area";
|
|
38786
38823
|
const TRANSITION_TARGET_ATTRIBUTE = "data-navi-route-transition-target";
|
|
38787
38824
|
// What a history entry remembers of the crossing that created it, in the
|
|
38788
|
-
// entry's own state: `{
|
|
38825
|
+
// entry's own state: `{ fromDepth, type, direction, duration }` (see
|
|
38826
|
+
// recordCrossing).
|
|
38789
38827
|
const CROSSING_STATE_KEY = "jsenv_route_transition";
|
|
38790
38828
|
const AREA_NAME = "navi-route-transition";
|
|
38791
38829
|
// The pictures carrying the movement, among everything else it takes along —
|
|
@@ -39442,51 +39480,35 @@ const normalizeRequest = transition => {
|
|
|
39442
39480
|
* What a TRAVERSAL asks for: the crossing it retraces.
|
|
39443
39481
|
*
|
|
39444
39482
|
* The entry a push creates remembers the crossing that created it (see
|
|
39445
|
-
* recordCrossing). A back onto the
|
|
39483
|
+
* recordCrossing). A back onto the entry that crossing came from undoes it —
|
|
39446
39484
|
* the same movement, the other way — and a forward onto an entry whose
|
|
39447
|
-
* crossing came from the
|
|
39485
|
+
* crossing came from the entry being left plays it again as it was. Both
|
|
39448
39486
|
* entries are read because each side is the only one that knows its case: the
|
|
39449
39487
|
* entry being LEFT says how it was reached (a back), the entry being REACHED
|
|
39450
39488
|
* says how it was reached (a forward).
|
|
39451
39489
|
*
|
|
39452
|
-
*
|
|
39453
|
-
*
|
|
39454
|
-
*
|
|
39455
|
-
*
|
|
39490
|
+
* An entry is named by its depth in the stack, never by its url: a replace
|
|
39491
|
+
* keeps the entry and its state while it rewrites the address — a param of
|
|
39492
|
+
* the page settling, a list writing where it stands — and the crossing is
|
|
39493
|
+
* still between the same two entries. A crossing always comes from below the
|
|
39494
|
+
* entry it is recorded on, so at most one of the two cases matches.
|
|
39456
39495
|
*
|
|
39457
39496
|
* Answers in the shape of readNavigationRequest, with every field said, so
|
|
39458
|
-
* that the relations have nothing left to answer for —
|
|
39459
|
-
*
|
|
39460
|
-
* travelled (see the watcher's onMove).
|
|
39497
|
+
* that the relations have nothing left to answer for — except the one written
|
|
39498
|
+
* for the exact way travelled, which outranks it (see the watcher's onMove).
|
|
39461
39499
|
*/
|
|
39462
|
-
const readTraversalReplay = ({
|
|
39463
|
-
|
|
39464
|
-
|
|
39465
|
-
|
|
39466
|
-
fromUrl,
|
|
39467
|
-
fromState
|
|
39468
|
-
}) => {
|
|
39469
|
-
const to = absoluteUrl(url);
|
|
39470
|
-
const from = absoluteUrl(fromUrl);
|
|
39471
|
-
if (!to || !from) {
|
|
39500
|
+
const readTraversalReplay = (state, fromState) => {
|
|
39501
|
+
const depthIn = navDepthOf(state);
|
|
39502
|
+
const depthOut = navDepthOf(fromState);
|
|
39503
|
+
if (depthIn === undefined || depthOut === undefined) {
|
|
39472
39504
|
return null;
|
|
39473
39505
|
}
|
|
39474
39506
|
const crossingIn = crossingRecordedOn(state);
|
|
39475
|
-
|
|
39476
|
-
const isForward = crossingIn !== null && crossingIn.from === from;
|
|
39477
|
-
const isBack = crossingOut !== null && crossingOut.from === to;
|
|
39478
|
-
if (isForward && isBack) {
|
|
39479
|
-
const depthIn = navDepthOf(state);
|
|
39480
|
-
const depthOut = navDepthOf(fromState);
|
|
39481
|
-
if (depthIn !== undefined && depthOut !== undefined && depthIn > depthOut) {
|
|
39482
|
-
return replayOf(crossingIn);
|
|
39483
|
-
}
|
|
39484
|
-
return replayOf(reverseCrossing(crossingOut));
|
|
39485
|
-
}
|
|
39486
|
-
if (isForward) {
|
|
39507
|
+
if (crossingIn !== null && crossingIn.fromDepth === depthOut) {
|
|
39487
39508
|
return replayOf(crossingIn);
|
|
39488
39509
|
}
|
|
39489
|
-
|
|
39510
|
+
const crossingOut = crossingRecordedOn(fromState);
|
|
39511
|
+
if (crossingOut !== null && crossingOut.fromDepth === depthIn) {
|
|
39490
39512
|
return replayOf(reverseCrossing(crossingOut));
|
|
39491
39513
|
}
|
|
39492
39514
|
return null;
|
|
@@ -39496,7 +39518,7 @@ const crossingRecordedOn = state => {
|
|
|
39496
39518
|
return null;
|
|
39497
39519
|
}
|
|
39498
39520
|
const crossing = state[CROSSING_STATE_KEY];
|
|
39499
|
-
if (!crossing || typeof crossing.
|
|
39521
|
+
if (!crossing || typeof crossing.fromDepth !== "number") {
|
|
39500
39522
|
return null;
|
|
39501
39523
|
}
|
|
39502
39524
|
return crossing;
|
|
@@ -39506,8 +39528,7 @@ const crossingRecordedOn = state => {
|
|
|
39506
39528
|
* Which way the history says a navigation goes, for a default that reads it
|
|
39507
39529
|
* (see defineRouteDefaultTransition): a push is one level deeper, a traversal
|
|
39508
39530
|
* goes where the depth of the entry it lands on puts it — back when that is
|
|
39509
|
-
* not known
|
|
39510
|
-
* on its level: null.
|
|
39531
|
+
* not known —, and anything else (a replace) stays on its level: null.
|
|
39511
39532
|
*/
|
|
39512
39533
|
const readHistoryDirection = (navigationType, {
|
|
39513
39534
|
state,
|
|
@@ -39558,8 +39579,25 @@ const replayOf = ({
|
|
|
39558
39579
|
type,
|
|
39559
39580
|
typeSaid: true,
|
|
39560
39581
|
duration,
|
|
39561
|
-
direction
|
|
39562
|
-
|
|
39582
|
+
direction
|
|
39583
|
+
};
|
|
39584
|
+
};
|
|
39585
|
+
|
|
39586
|
+
// What a press asked, field by field, over the crossing its traversal
|
|
39587
|
+
// retraces: a press naming only a direction keeps the movement retraced and
|
|
39588
|
+
// turns it round, as it would a relation's (see readNavigationRequest).
|
|
39589
|
+
const layerRequest = (request, replay) => {
|
|
39590
|
+
if (!replay) {
|
|
39591
|
+
return request;
|
|
39592
|
+
}
|
|
39593
|
+
if (!request) {
|
|
39594
|
+
return replay;
|
|
39595
|
+
}
|
|
39596
|
+
return {
|
|
39597
|
+
type: request.typeSaid ? request.type : replay.type,
|
|
39598
|
+
typeSaid: true,
|
|
39599
|
+
duration: request.duration === undefined ? replay.duration : request.duration,
|
|
39600
|
+
direction: request.direction === undefined ? replay.direction : request.direction
|
|
39563
39601
|
};
|
|
39564
39602
|
};
|
|
39565
39603
|
|
|
@@ -39645,9 +39683,10 @@ const rebuildWatcher = () => {
|
|
|
39645
39683
|
// reverse of a pair, a page from anywhere — and not over a relation
|
|
39646
39684
|
// written for this exact way: that line is the author's one tool for
|
|
39647
39685
|
// breaking reciprocity, and the back button is the way back it has to
|
|
39648
|
-
// reach. A request made by a link or a navTo() is never dropped
|
|
39649
|
-
//
|
|
39650
|
-
|
|
39686
|
+
// reach. A request made by a link or a navTo() is never dropped, not even
|
|
39687
|
+
// when its push was taken as a traversal: it is about this one crossing,
|
|
39688
|
+
// and a written relation is about every one.
|
|
39689
|
+
const request = layerRequest(navigationRequest, found && found.written ? null : navigationReplay);
|
|
39651
39690
|
if (!found && !request) {
|
|
39652
39691
|
// No relation says anything about these two and this navigation asked
|
|
39653
39692
|
// for nothing: they are side by side, and silence is the fact — not a
|
|
@@ -39698,6 +39737,10 @@ const rebuildWatcher = () => {
|
|
|
39698
39737
|
// start of every navigation, so they are always about the latest one.
|
|
39699
39738
|
let defaultTransition = null;
|
|
39700
39739
|
let navigationRequest = null;
|
|
39740
|
+
// The crossing a traversal retraces (see readTraversalReplay), kept apart from
|
|
39741
|
+
// what was asked: a relation written for the exact way drops the one and never
|
|
39742
|
+
// the other.
|
|
39743
|
+
let navigationReplay = null;
|
|
39701
39744
|
let navigationUrl = null;
|
|
39702
39745
|
// Where the document stands as the navigation begins — the other end of the
|
|
39703
39746
|
// crossing, and what lets the NEXT navigation be recognised as this one's way
|
|
@@ -39705,6 +39748,9 @@ let navigationUrl = null;
|
|
|
39705
39748
|
// on a browser without the Navigation API is announced from "popstate", where
|
|
39706
39749
|
// the address has already moved and location would answer with the destination.
|
|
39707
39750
|
let navigationFromUrl = null;
|
|
39751
|
+
// Where the entry being left stands in the stack: what a push's crossing names
|
|
39752
|
+
// as the entry it came from (see recordCrossing).
|
|
39753
|
+
let navigationFromDepth;
|
|
39708
39754
|
let navigationAnimated = false;
|
|
39709
39755
|
// "push", "replace", "traverse", … — a push is the one navigation that creates
|
|
39710
39756
|
// the entry a crossing is recorded on.
|
|
@@ -39733,17 +39779,18 @@ observeBeforeRouting(details => {
|
|
|
39733
39779
|
// Read before the document state moves, so the state peeked is the entry
|
|
39734
39780
|
// being left.
|
|
39735
39781
|
const fromState = documentStateSignal.peek();
|
|
39736
|
-
|
|
39737
|
-
//
|
|
39738
|
-
|
|
39739
|
-
|
|
39740
|
-
|
|
39741
|
-
|
|
39782
|
+
navigationFromDepth = navDepthOf(fromState);
|
|
39783
|
+
// A traversal is asked something only when a push to the entry next door
|
|
39784
|
+
// was taken as one, and then carries its press (see the integrations). What
|
|
39785
|
+
// else it asks is the crossing it retraces — reversed for a back, as it was
|
|
39786
|
+
// for a forward.
|
|
39787
|
+
navigationRequest = readNavigationRequest(details);
|
|
39788
|
+
navigationReplay = navigationType === "traverse" ? readTraversalReplay(details.state, fromState) : null;
|
|
39742
39789
|
navigationHistoryDirection = defaultTransition && defaultTransition.readsHistory ? readHistoryDirection(navigationType, {
|
|
39743
39790
|
state: details.state,
|
|
39744
39791
|
fromState
|
|
39745
39792
|
}) : undefined;
|
|
39746
|
-
if (relations.length === 0 && !defaultTransition && !navigationRequest) {
|
|
39793
|
+
if (relations.length === 0 && !defaultTransition && !navigationRequest && !navigationReplay) {
|
|
39747
39794
|
return;
|
|
39748
39795
|
}
|
|
39749
39796
|
holdRenderingForRouting();
|
|
@@ -39756,16 +39803,19 @@ observeBeforeRouting(details => {
|
|
|
39756
39803
|
}
|
|
39757
39804
|
});
|
|
39758
39805
|
observeAfterRouting(() => {
|
|
39759
|
-
const request = navigationRequest;
|
|
39806
|
+
const request = layerRequest(navigationRequest, navigationReplay);
|
|
39760
39807
|
const url = navigationUrl;
|
|
39761
39808
|
const fromUrl = navigationFromUrl;
|
|
39809
|
+
const fromDepth = navigationFromDepth;
|
|
39762
39810
|
const type = navigationType;
|
|
39763
39811
|
const historyDirection = navigationHistoryDirection;
|
|
39764
39812
|
// Read here and dropped here: a request answers for the navigation it was
|
|
39765
39813
|
// made on, and the next one is back to the relations.
|
|
39766
39814
|
navigationRequest = null;
|
|
39815
|
+
navigationReplay = null;
|
|
39767
39816
|
navigationUrl = null;
|
|
39768
39817
|
navigationFromUrl = null;
|
|
39818
|
+
navigationFromDepth = undefined;
|
|
39769
39819
|
navigationType = null;
|
|
39770
39820
|
navigationHistoryDirection = undefined;
|
|
39771
39821
|
// A default reading the history plays between two pages a level apart: not
|
|
@@ -39804,7 +39854,7 @@ observeAfterRouting(() => {
|
|
|
39804
39854
|
if (type === "push") {
|
|
39805
39855
|
recordCrossing({
|
|
39806
39856
|
url,
|
|
39807
|
-
|
|
39857
|
+
fromDepth,
|
|
39808
39858
|
decision: navigationDecision
|
|
39809
39859
|
});
|
|
39810
39860
|
}
|
|
@@ -39822,15 +39872,14 @@ observeAfterRouting(() => {
|
|
|
39822
39872
|
// reached by one keeps the crossing that led to where it stands.
|
|
39823
39873
|
const recordCrossing = ({
|
|
39824
39874
|
url,
|
|
39825
|
-
|
|
39875
|
+
fromDepth,
|
|
39826
39876
|
decision
|
|
39827
39877
|
}) => {
|
|
39828
|
-
if (!decision) {
|
|
39878
|
+
if (!decision || fromDepth === undefined) {
|
|
39829
39879
|
return;
|
|
39830
39880
|
}
|
|
39831
39881
|
const to = absoluteUrl(url);
|
|
39832
|
-
|
|
39833
|
-
if (!to || !from) {
|
|
39882
|
+
if (!to) {
|
|
39834
39883
|
return;
|
|
39835
39884
|
}
|
|
39836
39885
|
if (documentUrlSignal.peek() !== to) {
|
|
@@ -39838,7 +39887,7 @@ const recordCrossing = ({
|
|
|
39838
39887
|
return;
|
|
39839
39888
|
}
|
|
39840
39889
|
const crossing = {
|
|
39841
|
-
|
|
39890
|
+
fromDepth
|
|
39842
39891
|
};
|
|
39843
39892
|
if (decision.type !== undefined) {
|
|
39844
39893
|
crossing.type = decision.type;
|
|
@@ -44871,15 +44920,16 @@ const armOutsidePressClose = (
|
|
|
44871
44920
|
* follows a new `defaultValue` on its own (see followDefaultValue in
|
|
44872
44921
|
* ui_state_controller.js) — and this is what throws that edit away.
|
|
44873
44922
|
*
|
|
44874
|
-
* On top of whichever value is picked, intent
|
|
44875
|
-
*
|
|
44876
|
-
*
|
|
44877
|
-
*
|
|
44878
|
-
* where a delay is felt hardest —
|
|
44879
|
-
* trigger and pressing it are free.
|
|
44880
|
-
*
|
|
44881
|
-
*
|
|
44882
|
-
*
|
|
44923
|
+
* On top of whichever value is picked, intent warms the content: a press on
|
|
44924
|
+
* what opens the popup, and but for "while-opened" a pointer entering the
|
|
44925
|
+
* popup's anchor or focus landing in it, builds the content ahead of the click
|
|
44926
|
+
* that will open it. Deferring the build to the opening puts its whole cost in
|
|
44927
|
+
* the frame right after the click — the frame where a delay is felt hardest —
|
|
44928
|
+
* while the ~100-300ms between hovering a trigger and pressing it are free.
|
|
44929
|
+
* The warming render starts at the frame after the one that follows the
|
|
44930
|
+
* intent: nothing here needs the content in the DOM before the click, only
|
|
44931
|
+
* before the open that follows it, and a build started at once would hold
|
|
44932
|
+
* back the frame that shows the hover or the focus.
|
|
44883
44933
|
*
|
|
44884
44934
|
* Under a finger, `pointerover` is not an intent yet: it arrives with the
|
|
44885
44935
|
* `pointerdown` of every touch, the ones starting a scroll included, and at
|
|
@@ -44899,7 +44949,12 @@ const armOutsidePressClose = (
|
|
|
44899
44949
|
* press does not open (`data-open-on`: a picker opened by a hold, or only by a
|
|
44900
44950
|
* command) says nothing; the keyboard still opens it, so focus there warms.
|
|
44901
44951
|
*
|
|
44902
|
-
*
|
|
44952
|
+
* An opening press warms whatever the value. A popup with no anchor — a sheet,
|
|
44953
|
+
* a side panel, a layer opened by a button — has nothing else saying it is
|
|
44954
|
+
* about to open, and under a finger the ~100ms a tap is held are as free as a
|
|
44955
|
+
* hover.
|
|
44956
|
+
*
|
|
44957
|
+
* "while-opened" content is warmed by that press only, never by a hover or a
|
|
44903
44958
|
* focus. That mode promises content built fresh for the gesture that opens
|
|
44904
44959
|
* it, and mounted only while that gesture and its opening last: callers lean
|
|
44905
44960
|
* on it (several pickers sharing one set of content ids, because only one
|
|
@@ -44916,15 +44971,16 @@ const armOutsidePressClose = (
|
|
|
44916
44971
|
* The press builds the content when it starts, a touch once it has been held
|
|
44917
44972
|
* as above: the announcement carries the pointerdown that made it. A press
|
|
44918
44973
|
* released before its build leaves the building to the open its click asks
|
|
44919
|
-
* for.
|
|
44920
|
-
*
|
|
44974
|
+
* for. A press ending without an open keeps what it built, as a hover does:
|
|
44975
|
+
* the next press finds it there. Under "while-opened" it throws the content
|
|
44976
|
+
* away — its click reaching the document with the popup still closed, no
|
|
44921
44977
|
* click coming after the release, the browser taking the gesture
|
|
44922
44978
|
* (`pointercancel`), or the next press starting, before any of its own
|
|
44923
44979
|
* handlers run: one press at a time holds a content. A keyboard opening builds
|
|
44924
44980
|
* at open time. A "while-opened" popup with an `onOpen` is not warmed by the
|
|
44925
44981
|
* press: that callback runs before the content is built (see
|
|
44926
44982
|
* open_controller.js), and a content seeding itself from what it writes must
|
|
44927
|
-
* be built after it.
|
|
44983
|
+
* be built after it. For the other values, a press, a hover and a focus build
|
|
44928
44984
|
* ahead of `onOpen` all the same.
|
|
44929
44985
|
*/
|
|
44930
44986
|
|
|
@@ -44961,11 +45017,14 @@ const cancelIdle = (id) =>
|
|
|
44961
45017
|
? cancelIdleCallback(id)
|
|
44962
45018
|
: clearTimeout(id);
|
|
44963
45019
|
|
|
44964
|
-
// How long a finger rests on an anchor before it warms it:
|
|
44965
|
-
// which the browser takes a touch moving at reading speed
|
|
44966
|
-
//
|
|
44967
|
-
//
|
|
44968
|
-
|
|
45020
|
+
// How long a finger rests on an anchor or an opener before it warms it: just
|
|
45021
|
+
// past the ~35ms at which the browser takes a touch moving at reading speed
|
|
45022
|
+
// for a scroll. A tap is held ~100ms, and the hold ends at a frame, which a
|
|
45023
|
+
// phone's busy main thread runs late: at 80ms a 100ms tap on 2v2's settings
|
|
45024
|
+
// wheel (CPU 6x) lifted before that frame 5 times out of 7 and was warmed by
|
|
45025
|
+
// nothing. The price is a scroll that starts slowly enough to be taken past
|
|
45026
|
+
// 40ms: it builds what the open would have built.
|
|
45027
|
+
const TOUCH_WARM_HOLD_MS = 40;
|
|
44969
45028
|
|
|
44970
45029
|
const usePopupContentMount = (
|
|
44971
45030
|
openController,
|
|
@@ -45128,9 +45187,9 @@ const usePopupContentMount = (
|
|
|
45128
45187
|
anchorElement.removeEventListener("focusin", onFocusIn);
|
|
45129
45188
|
};
|
|
45130
45189
|
}, [contentMounted, anchor, mount]);
|
|
45131
|
-
// Warm on an opening press
|
|
45132
|
-
//
|
|
45133
|
-
//
|
|
45190
|
+
// Warm on an opening press (see the top comment). Told by the popup's own
|
|
45191
|
+
// element, which hears the announcement where it hears the opening request:
|
|
45192
|
+
// `onnavi_open_press` beside each `onnavi_request_open`.
|
|
45134
45193
|
const stopPressWarmRef = useRef(null);
|
|
45135
45194
|
openController.onOpeningPress =
|
|
45136
45195
|
mount === "while-opened"
|
|
@@ -45156,7 +45215,21 @@ const usePopupContentMount = (
|
|
|
45156
45215
|
stopWatching();
|
|
45157
45216
|
};
|
|
45158
45217
|
}
|
|
45159
|
-
:
|
|
45218
|
+
: (openPressEvent) => {
|
|
45219
|
+
// Two fingers on two of its openers are one build.
|
|
45220
|
+
if (contentMountedRef.current || stopPressWarmRef.current) {
|
|
45221
|
+
return;
|
|
45222
|
+
}
|
|
45223
|
+
stopPressWarmRef.current = requestBuildOnPress(openPressEvent, {
|
|
45224
|
+
onBuild: () => {
|
|
45225
|
+
stopPressWarmRef.current = null;
|
|
45226
|
+
setContentMounted(true);
|
|
45227
|
+
},
|
|
45228
|
+
onGiveUp: () => {
|
|
45229
|
+
stopPressWarmRef.current = null;
|
|
45230
|
+
},
|
|
45231
|
+
});
|
|
45232
|
+
};
|
|
45160
45233
|
useEffect(() => {
|
|
45161
45234
|
return () => {
|
|
45162
45235
|
stopPressWarmRef.current?.();
|
|
@@ -61648,8 +61721,8 @@ a.navi_button {
|
|
|
61648
61721
|
outline-color: var(--button-outline-color);
|
|
61649
61722
|
outline-offset: var(--button-outline-offset);
|
|
61650
61723
|
transition-property: transform;
|
|
61651
|
-
transition-duration: .
|
|
61652
|
-
transition-timing-function: cubic-bezier(.
|
|
61724
|
+
transition-duration: .25s;
|
|
61725
|
+
transition-timing-function: cubic-bezier(.2, 0, 0, 1);
|
|
61653
61726
|
position: relative;
|
|
61654
61727
|
|
|
61655
61728
|
& .navi_button_shadow {
|
|
@@ -61692,7 +61765,7 @@ a.navi_button {
|
|
|
61692
61765
|
|
|
61693
61766
|
&[data-pressed] {
|
|
61694
61767
|
& .navi_button_content {
|
|
61695
|
-
transition-duration:
|
|
61768
|
+
transition-duration: .1s;
|
|
61696
61769
|
transform: scale(.9);
|
|
61697
61770
|
}
|
|
61698
61771
|
}
|
|
@@ -73769,10 +73842,12 @@ const giveUpOnControlsHoldingPopup = (controlsHolding, reason) => {
|
|
|
73769
73842
|
* itself on it (navi_open_press), --navi-toggle reads its aria-expanded. The
|
|
73770
73843
|
* popup proper — its open controller, its box, its backdrop, its focus and
|
|
73771
73844
|
* pseudo-class wiring — is built at the first request: an open, a press about
|
|
73772
|
-
* to open it, its signal or its `open` saying open. A
|
|
73773
|
-
*
|
|
73774
|
-
*
|
|
73775
|
-
*
|
|
73845
|
+
* to open it, its signal or its `open` saying open. A press builds what the
|
|
73846
|
+
* popup holds along with it, as it warms the content of a popup already built
|
|
73847
|
+
* (see popup_content_mount.js): the click that follows only opens. A list
|
|
73848
|
+
* whose rows each hold a few popups mounts hundreds of them, and would pay for
|
|
73849
|
+
* every one at every mount, for openings that mostly never come. Built once,
|
|
73850
|
+
* the popup stays: the next opening finds it there.
|
|
73776
73851
|
*
|
|
73777
73852
|
* Nothing about where the popup goes is needed at rest: a popover reads its
|
|
73778
73853
|
* anchor at the opening, from the request.
|
|
@@ -76168,6 +76243,11 @@ const DialogStandIn = props => {
|
|
|
76168
76243
|
...props,
|
|
76169
76244
|
ref: dialogRef,
|
|
76170
76245
|
defaultOpen: builtReason === "interaction" ? "interaction" : props.defaultOpen
|
|
76246
|
+
// Built by a press on what opens it: the content comes with it, and
|
|
76247
|
+
// stays, as a "from-first-open" content does once built (see
|
|
76248
|
+
// popup_stand_in.js).
|
|
76249
|
+
,
|
|
76250
|
+
mount: builtReason === "press" ? "always" : props.mount
|
|
76171
76251
|
});
|
|
76172
76252
|
}
|
|
76173
76253
|
return jsx("dialog", {
|
|
@@ -78133,6 +78213,11 @@ const PopoverStandIn = props => {
|
|
|
78133
78213
|
...props,
|
|
78134
78214
|
ref: popoverRef,
|
|
78135
78215
|
defaultOpen: builtReason === "interaction" ? "interaction" : props.defaultOpen
|
|
78216
|
+
// Built by a press on what opens it: the content comes with it, and
|
|
78217
|
+
// stays, as a "from-first-open" content does once built (see
|
|
78218
|
+
// popup_stand_in.js).
|
|
78219
|
+
,
|
|
78220
|
+
mount: builtReason === "press" ? "always" : props.mount
|
|
78136
78221
|
});
|
|
78137
78222
|
}
|
|
78138
78223
|
return jsx("div", {
|