@jsenv/navi 0.29.391 → 0.29.393

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.
@@ -29164,39 +29164,43 @@ const idUsageMap = new Map();
29164
29164
  // Keys found in the entry with nobody to claim them, already reported.
29165
29165
  const orphanKeysReported = new Set();
29166
29166
  const useNavStateWithWarnings = (id, options) => {
29167
- const idRef = useRef(undefined);
29168
- if (idRef.current !== id) {
29169
- const oldId = idRef.current;
29170
- idUsageMap.delete(oldId);
29171
- idRef.current = id;
29167
+ const ownerRef = useRef(null);
29168
+ if (!ownerRef.current) {
29169
+ ownerRef.current = {};
29170
+ }
29171
+ const owner = ownerRef.current;
29172
+ // Claimed during render so warnAboutOrphanGeneratedKeys sees every id of
29173
+ // the commit, including the ones whose effect has not run yet. The conflict
29174
+ // is judged in the effect: when a screen replaces another in one commit,
29175
+ // preact renders the new children before unmounting the old ones, so at
29176
+ // render time the id may still be held by a component about to go.
29177
+ if (id !== undefined && !idUsageMap.has(id)) {
29178
+ idUsageMap.set(id, { owner, stackTrace: new Error().stack });
29179
+ }
29172
29180
 
29181
+ useEffect(() => {
29182
+ if (id === undefined) {
29183
+ return undefined;
29184
+ }
29173
29185
  const usage = idUsageMap.get(id);
29174
- if (!usage) {
29175
- idUsageMap.set(id, {
29176
- stackTrace: new Error().stack,
29177
- });
29178
- } else {
29186
+ if (usage && usage.owner !== owner) {
29179
29187
  console.warn(
29180
29188
  `useNavState ID conflict detected!
29181
29189
  ID "${id}" is already in use by another component.
29182
29190
  This can cause UI state conflicts and unexpected behavior.
29183
29191
  Consider using unique IDs for each component instance.`,
29184
29192
  );
29185
- }
29186
- }
29187
-
29188
- useEffect(() => {
29189
- // Registered here as well as in the render above: preact/compat's
29190
- // Suspense parks a subtree by running every hook cleanup in it, and the
29191
- // render resuming it carries the same id.
29192
- if (!idUsageMap.has(id)) {
29193
- idUsageMap.set(id, {
29194
- stackTrace: new Error().stack,
29195
- });
29193
+ } else {
29194
+ // Also set when absent: preact/compat's Suspense parks a subtree by
29195
+ // running every hook cleanup in it, and the render resuming it carries
29196
+ // the same id.
29197
+ idUsageMap.set(id, { owner, stackTrace: new Error().stack });
29196
29198
  }
29197
29199
  warnAboutOrphanGeneratedKeys();
29198
29200
  return () => {
29199
- idUsageMap.delete(id);
29201
+ if (idUsageMap.get(id)?.owner === owner) {
29202
+ idUsageMap.delete(id);
29203
+ }
29200
29204
  };
29201
29205
  }, [id]);
29202
29206
 
@@ -30237,9 +30241,13 @@ installImportMetaCssBuild(import.meta);
30237
30241
  * - a bar only one state has never meets a counterpart. It belongs to the page
30238
30242
  * that has it, so it travels with that page — leaving by the keyframes the
30239
30243
  * page being left leaves by, arriving by the ones the page arriving arrives
30240
- * by — instead of going out with the render. Under the pages, so a page
30241
- * coming over it covers it — a popup over them instead, standing where it
30242
- * stands in the document (see the z-order in route_transition.jsx).
30244
+ * by — instead of going out with the render. Over that page, as it is at
30245
+ * rest: the page runs under it, and what it paints outside its box (a button
30246
+ * standing up out of a tab bar) is not cut by its own page. Under the pages
30247
+ * only when its page is covered by the other one — a cover-* movement — so
30248
+ * the sheet comes over it; a popup over everything, standing where it
30249
+ * stands in the document (see the z-order in route_transition.jsx). Which
30250
+ * side a bar is on is said by a class on its group, written here.
30243
30251
  *
30244
30252
  * A popup shown in the top layer is furniture of the same kind, and its case
30245
30253
  * is the sharper one: it is a DOM descendant of the area, yet painted outside
@@ -30317,11 +30325,17 @@ const FURNITURE_NAME_PREFIX = "navi-transition-furniture-";
30317
30325
  const TOP_LAYER_WALL_SELECTOR =
30318
30326
  ".navi_dialog:modal, .navi_popover_backdrop:popover-open";
30319
30327
  const WALL_ATTRIBUTE = "data-navi-transition-wall";
30320
- // Worn by a bar both states have, from the hold on: its two pictures are one
30321
- // group, and the group is ordered over the pages (route_transition.jsx). Only
30322
- // a bar — a popup's class is written by layout/popup_css.js, and a second rule
30323
- // on the same property would replace it.
30324
- const SHARED_ATTRIBUTE = "data-navi-transition-furniture-shared";
30328
+ // Which side of the movement a bar is on, worn by the bar and read by the
30329
+ // browser as the class of its group (the CSS below): "leaving" from the first
30330
+ // picture, "arriving" for a bar the state arriving brought, "shared" for one
30331
+ // that stands in both states, written over "leaving" at the hold. The group's
30332
+ // class is the one captured with the LAST state the element stands in, so a
30333
+ // bar only the state being left has keeps "leaving" from the first capture,
30334
+ // and a shared one takes "shared" from the second. The z-order in
30335
+ // route_transition.jsx is written on these three. Only a bar — a popup's
30336
+ // class is written by layout/popup_css.js, and a second rule on the same
30337
+ // property would replace it.
30338
+ const FURNITURE_ATTRIBUTE = "data-navi-transition-furniture";
30325
30339
  // What the wall paints, resolved on the matched element in both cases (the
30326
30340
  // dialog for its ::backdrop, the popover's wall for itself): the same two
30327
30341
  // properties, copied onto the stand-in.
@@ -30330,7 +30344,15 @@ const WALL_PROPERTIES = ["--backdrop-background", "--backdrop-filter"];
30330
30344
  // The pictures the wall is painted into: the pages', and every bar's own.
30331
30345
  const FIXED_BAR_SELECTOR$1 = ".navi_fixed_bar";
30332
30346
 
30333
- const TRANSITION_FURNITURE_CSS = /* css */ `.navi_fixed_bar[data-navi-transition-furniture-shared] {
30347
+ const TRANSITION_FURNITURE_CSS = /* css */ `.navi_fixed_bar[data-navi-transition-furniture="leaving"] {
30348
+ view-transition-class: navi_furniture_leaving;
30349
+ }
30350
+
30351
+ .navi_fixed_bar[data-navi-transition-furniture="arriving"] {
30352
+ view-transition-class: navi_furniture_arriving;
30353
+ }
30354
+
30355
+ .navi_fixed_bar[data-navi-transition-furniture="shared"] {
30334
30356
  view-transition-class: navi_furniture_shared;
30335
30357
  }
30336
30358
 
@@ -30403,7 +30425,7 @@ const nameTransitionFurniture = (owner, areaElement) => {
30403
30425
  furnitureOwner = owner;
30404
30426
  namedElements = new Set();
30405
30427
  }
30406
- nameFurnitureAround(areaElement);
30428
+ nameFurnitureAround(areaElement, "leaving");
30407
30429
  const sources = paintTransitionWalls(areaElement);
30408
30430
  // The state being left has walls: what no picture covers starts dimmed.
30409
30431
  // The frame the first picture is taken on shows the live document, so the
@@ -30430,10 +30452,10 @@ const holdTransitionFurniture = (owner, areaElement) => {
30430
30452
  if (!element.isConnected) {
30431
30453
  namesLeaving.push(nameByElement.get(element));
30432
30454
  } else if (element.matches(FIXED_BAR_SELECTOR$1)) {
30433
- element.setAttribute(SHARED_ATTRIBUTE, "");
30455
+ element.setAttribute(FURNITURE_ATTRIBUTE, "shared");
30434
30456
  }
30435
30457
  }
30436
- const namesArriving = nameFurnitureAround(areaElement);
30458
+ const namesArriving = nameFurnitureAround(areaElement, "arriving");
30437
30459
  const sources = paintTransitionWalls(areaElement);
30438
30460
  // The state arriving has walls: what no picture covers ends dimmed. Painted
30439
30461
  // from the state being left when that one had walls (they stay up if both
@@ -30483,7 +30505,8 @@ const holdTransitionFurniture = (owner, areaElement) => {
30483
30505
 
30484
30506
  // Returns the elements it had to name, which are the ones the state arriving
30485
30507
  // brought: everything else was already wearing its name from the first pass.
30486
- const nameFurnitureAround = (areaElement) => {
30508
+ // `side` is what a bar named here is told it is on (see FURNITURE_ATTRIBUTE).
30509
+ const nameFurnitureAround = (areaElement, side) => {
30487
30510
  const namesAdded = [];
30488
30511
  for (const element of document.querySelectorAll(FURNITURE_SELECTOR)) {
30489
30512
  if (namedElements.has(element)) {
@@ -30509,6 +30532,9 @@ const nameFurnitureAround = (areaElement) => {
30509
30532
  nameByElement.set(element, name);
30510
30533
  }
30511
30534
  element.style.setProperty(NAME_PROPERTY$1, name);
30535
+ if (element.matches(FIXED_BAR_SELECTOR$1)) {
30536
+ element.setAttribute(FURNITURE_ATTRIBUTE, side);
30537
+ }
30512
30538
  namedElements.add(element);
30513
30539
  namesAdded.push(name);
30514
30540
  }
@@ -30558,7 +30584,7 @@ const releaseTransitionFurniture = (owner) => {
30558
30584
  furnitureOwner = null;
30559
30585
  for (const element of namedElements) {
30560
30586
  element.style.removeProperty(NAME_PROPERTY$1);
30561
- element.removeAttribute(SHARED_ATTRIBUTE);
30587
+ element.removeAttribute(FURNITURE_ATTRIBUTE);
30562
30588
  }
30563
30589
  namedElements = new Set();
30564
30590
  if (travelStyleElement) {
@@ -30881,7 +30907,20 @@ const measureTransitionWindowState = (element) => {
30881
30907
  };
30882
30908
  };
30883
30909
 
30884
- const holdTransitionWindow = (owner, element, stateBefore) => {
30910
+ /**
30911
+ * @param {object} options
30912
+ * @param {boolean} options.furnitureLive - Whether the bars stay live under
30913
+ * the pictures for the movement (a travel), or are pictures of their own
30914
+ * ordered over the page they belong to (a route transition, see
30915
+ * transition_furniture.js). Decides how far the cut may be opened for the
30916
+ * picture being left — see bandTheCutMayBeRelaxedTo.
30917
+ */
30918
+ const holdTransitionWindow = (
30919
+ owner,
30920
+ element,
30921
+ stateBefore,
30922
+ { furnitureLive },
30923
+ ) => {
30885
30924
  const bandBefore = stateBefore.band;
30886
30925
  const rectAfter = element.getBoundingClientRect();
30887
30926
  const bandAfter = readBand();
@@ -30915,7 +30954,9 @@ const holdTransitionWindow = (owner, element, stateBefore) => {
30915
30954
  style.setProperty(WINDOW_OLD_LEFT_PROPERTY, `${rectBefore.left}px`);
30916
30955
  style.setProperty(WINDOW_NEW_TOP_PROPERTY, `${rectAfter.top}px`);
30917
30956
  style.setProperty(WINDOW_NEW_LEFT_PROPERTY, `${rectAfter.left}px`);
30918
- const oldBand = bandTheCutMayBeRelaxedTo(bandBefore, bandAfter, rectAfter);
30957
+ const oldBand = furnitureLive
30958
+ ? bandTheCutMayBeRelaxedTo(bandBefore, bandAfter, rectAfter)
30959
+ : bandBefore;
30919
30960
  style.setProperty(OLD_BAND_TOP_PROPERTY, `${oldBand.top}px`);
30920
30961
  style.setProperty(OLD_BAND_RIGHT_PROPERTY, `${oldBand.right}px`);
30921
30962
  style.setProperty(OLD_BAND_BOTTOM_PROPERTY, `${oldBand.bottom}px`);
@@ -31078,18 +31119,25 @@ const readBand = () => {
31078
31119
  };
31079
31120
  };
31080
31121
 
31081
- // How far the cut may be opened for the picture being left — the band its own
31082
- // state kept free, which is the whole point of photographing it: furniture
31083
- // present in only one of the two states is not the frame, it is part of what
31084
- // changes, and cutting the page being left at a bar it never had shows its
31085
- // header being sliced instead of leaving.
31122
+ // How far the cut may be opened for the picture being left when the furniture
31123
+ // is LIVE under the pictures — the band its own state kept free, which is the
31124
+ // whole point of photographing it: furniture present in only one of the two
31125
+ // states is not the frame, it is part of what changes, and cutting the page
31126
+ // being left at a bar it never had shows its header being sliced instead of
31127
+ // leaving.
31086
31128
  //
31087
31129
  // Never past what the picture ARRIVING needs, though: the cut is one line for
31088
31130
  // both pictures, so opening it for one opens it for the other. A box that runs
31089
- // under the furniture it arrives beside — a page scrolled below a top bar —
31090
- // would then be watched painting over that bar for the length of the movement,
31091
- // which is what the cut exists to prevent. On such an edge the arriving band
31092
- // stands, and the page being left is cut as it always was.
31131
+ // under the live furniture it arrives beside — a page scrolled below a top bar
31132
+ // — would then be watched painting over that bar for the length of the
31133
+ // movement, which is what the cut exists to prevent. On such an edge the
31134
+ // arriving band stands, and the page being left is cut as it always was.
31135
+ //
31136
+ // With the furniture photographed (a route transition) none of this holds: a
31137
+ // bar only the arriving state has is a picture ordered over the page it
31138
+ // belongs to, and a page arriving under it paints nothing over it. The band
31139
+ // of the state being left is then published as it was, so the page being
31140
+ // left is never cut at a bar it never had.
31093
31141
  const bandTheCutMayBeRelaxedTo = (bandBefore, bandAfter, rectAfter) => {
31094
31142
  return {
31095
31143
  top: rectAfter.top < bandAfter.top ? bandAfter.top : bandBefore.top,
@@ -31282,6 +31330,16 @@ const startViewTransition$1 = ensureDocumentStartViewTransition();
31282
31330
  const TRANSITION_ATTRIBUTE = "data-navi-route-transition";
31283
31331
  const TRANSITION_TYPE_ATTRIBUTE = "data-navi-route-transition-type";
31284
31332
  const TRANSITION_DURATION_PROPERTY = "--navi-route-transition-duration";
31333
+ // Which page the other one COVERS, when the movement is one page over the
31334
+ // other: "old" (the page arriving comes over the page being left) or "new"
31335
+ // (the page being left slides off the page arriving). Published by the type
31336
+ // as a value on the root, like its keyframes (see the css), and mirrored as an
31337
+ // attribute for the length of the transition so the rules that depend on it
31338
+ // — which page is on top, what is cut, where the furniture goes — can be
31339
+ // written statically. Absent for a movement where neither page covers the
31340
+ // other.
31341
+ const TRANSITION_COVERED_PROPERTY = "--navi-route-transition-covered";
31342
+ const TRANSITION_COVERED_ATTRIBUTE = "data-navi-route-transition-covered";
31285
31343
  // What the movement is played on. The root snapshot spans the viewport, and
31286
31344
  // the regions of elements captured on their own (a named bar) are BLANK in it
31287
31345
  // — a page sliding vertically then drags a blank band across the screen where
@@ -31364,7 +31422,7 @@ const css$12 = /* css */`:root[data-navi-route-transition] [data-navi-route-tran
31364
31422
  z-index: 1;
31365
31423
  }
31366
31424
 
31367
- &::view-transition-group(.navi_furniture_shared) {
31425
+ &::view-transition-group(.navi_furniture_leaving), &::view-transition-group(.navi_furniture_arriving), &::view-transition-group(.navi_furniture_shared) {
31368
31426
  z-index: 2;
31369
31427
  }
31370
31428
 
@@ -31372,6 +31430,18 @@ const css$12 = /* css */`:root[data-navi-route-transition] [data-navi-route-tran
31372
31430
  z-index: 3;
31373
31431
  }
31374
31432
 
31433
+ &[data-navi-route-transition-covered="old"] {
31434
+ &::view-transition-group(.navi_furniture_leaving) {
31435
+ z-index: 0;
31436
+ }
31437
+ }
31438
+
31439
+ &[data-navi-route-transition-covered="new"] {
31440
+ &::view-transition-group(.navi_furniture_arriving) {
31441
+ z-index: 0;
31442
+ }
31443
+ }
31444
+
31375
31445
  &::view-transition-group(*), &::view-transition-old(*), &::view-transition-new(*) {
31376
31446
  animation-duration: var(--navi-route-transition-duration, .3s);
31377
31447
  }
@@ -31411,6 +31481,38 @@ const css$12 = /* css */`:root[data-navi-route-transition] [data-navi-route-tran
31411
31481
  left: calc(var(--navi-transition-window-new-left) - var(--navi-transition-window-left));
31412
31482
  }
31413
31483
 
31484
+ &[data-navi-route-transition-target="area"] {
31485
+ &[data-navi-route-transition-covered="old"] {
31486
+ &::view-transition-old(navi-route-transition) {
31487
+ clip-path: polygon(calc(var(--navi-transition-old-band-left) - var(--navi-transition-window-old-left))
31488
+ calc(var(--navi-transition-old-band-top) - var(--navi-transition-window-old-top)),
31489
+ calc(100dvw - var(--navi-transition-old-band-right) - var(--navi-transition-window-old-left))
31490
+ calc(var(--navi-transition-old-band-top) - var(--navi-transition-window-old-top)),
31491
+ calc(100dvw - var(--navi-transition-old-band-right) - var(--navi-transition-window-old-left))
31492
+ calc(100dvh - var(--navi-transition-old-band-bottom) - var(--navi-transition-window-old-top)),
31493
+ calc(var(--navi-transition-old-band-left) - var(--navi-transition-window-old-left))
31494
+ calc(100dvh - var(--navi-transition-old-band-bottom) - var(--navi-transition-window-old-top)));
31495
+ }
31496
+ }
31497
+
31498
+ &[data-navi-route-transition-covered="new"] {
31499
+ &::view-transition-new(navi-route-transition) {
31500
+ clip-path: polygon(calc(var(--navi-safe-area-inset-left) +
31501
+ var(--navi-transition-cover-left) - var(--navi-transition-window-new-left))
31502
+ calc(var(--navi-safe-area-inset-top) +
31503
+ var(--navi-transition-cover-top) - var(--navi-transition-window-new-top)),
31504
+ calc(100dvw - var(--navi-safe-area-inset-right) - var(--navi-transition-cover-right) - var(--navi-transition-window-new-left))
31505
+ calc(var(--navi-safe-area-inset-top) +
31506
+ var(--navi-transition-cover-top) - var(--navi-transition-window-new-top)),
31507
+ calc(100dvw - var(--navi-safe-area-inset-right) - var(--navi-transition-cover-right) - var(--navi-transition-window-new-left))
31508
+ calc(100dvh - var(--navi-safe-area-inset-bottom) - var(--navi-transition-cover-bottom) - var(--navi-transition-window-new-top)),
31509
+ calc(var(--navi-safe-area-inset-left) +
31510
+ var(--navi-transition-cover-left) - var(--navi-transition-window-new-left))
31511
+ calc(100dvh - var(--navi-safe-area-inset-bottom) - var(--navi-transition-cover-bottom) - var(--navi-transition-window-new-top)));
31512
+ }
31513
+ }
31514
+ }
31515
+
31414
31516
  &[data-navi-route-transition-type] {
31415
31517
  &::view-transition-old(root), &::view-transition-new(root), &::view-transition-old(navi-route-transition), &::view-transition-new(navi-route-transition) {
31416
31518
  object-fit: none;
@@ -31495,10 +31597,18 @@ const css$12 = /* css */`:root[data-navi-route-transition] [data-navi-route-tran
31495
31597
  }
31496
31598
 
31497
31599
  &[data-navi-route-transition-type="cover-right"], &[data-navi-route-transition-type="cover-left"], &[data-navi-route-transition-type="cover-bottom"], &[data-navi-route-transition-type="cover-top"] {
31600
+ &[data-navi-route-transition="forward"] {
31601
+ --navi-route-transition-covered: old;
31602
+ }
31603
+
31498
31604
  &[data-navi-route-transition="back"] {
31499
- &::view-transition-old(root), &::view-transition-old(navi-route-transition) {
31500
- z-index: 1;
31501
- }
31605
+ --navi-route-transition-covered: new;
31606
+ }
31607
+ }
31608
+
31609
+ &[data-navi-route-transition-covered="new"] {
31610
+ &::view-transition-old(root), &::view-transition-old(navi-route-transition) {
31611
+ z-index: 1;
31502
31612
  }
31503
31613
  }
31504
31614
 
@@ -31701,6 +31811,11 @@ const RouteTransitionArea = ({
31701
31811
  * }
31702
31812
  * }
31703
31813
  *
31814
+ * A type of the application's own that plays one page OVER the other says
31815
+ * which one is covered, next to its keyframes:
31816
+ * `--navi-route-transition-covered: old` (the page arriving comes over the
31817
+ * page being left) or `new` (the page being left slides off the page
31818
+ * arriving) — see docs/route_transitions.md, "Custom movements".
31704
31819
  * Whatever is written here is what EVERY crossing of the pair plays. One
31705
31820
  * crossing can ask for something else — `<Link routeTransition>`, or
31706
31821
  * navTo(url, { routeTransition }) — which overrides this field by field, for
@@ -32344,6 +32459,12 @@ const beginTransition = ({
32344
32459
  documentElement.setAttribute(TRANSITION_ATTRIBUTE, direction);
32345
32460
  if (type) {
32346
32461
  documentElement.setAttribute(TRANSITION_TYPE_ATTRIBUTE, type);
32462
+ // Read once the type is worn, which is what makes the type's value
32463
+ // resolve; a value a type does not publish leaves the attribute off.
32464
+ const covered = getComputedStyle(documentElement).getPropertyValue(TRANSITION_COVERED_PROPERTY).trim();
32465
+ if (covered === "old" || covered === "new") {
32466
+ documentElement.setAttribute(TRANSITION_COVERED_ATTRIBUTE, covered);
32467
+ }
32347
32468
  }
32348
32469
  // Looked up per transition, not once: the area is the application's own
32349
32470
  // element and follows its lifecycle — a page layout without bars has none,
@@ -32446,7 +32567,9 @@ const beginTransition = ({
32446
32567
  // replaced holds nothing: what it wore was taken off at the takeover.
32447
32568
  if (areaElement && currentTransition === transition) {
32448
32569
  holdTransitionFurniture(transition, areaElement);
32449
- holdTransitionWindow(transition, areaElement, areaStateBefore);
32570
+ holdTransitionWindow(transition, areaElement, areaStateBefore, {
32571
+ furnitureLive: false
32572
+ });
32450
32573
  }
32451
32574
  });
32452
32575
  const end = () => {
@@ -32481,6 +32604,7 @@ const releaseTransitionRoot = transition => {
32481
32604
  const documentElement = document.documentElement;
32482
32605
  documentElement.removeAttribute(TRANSITION_ATTRIBUTE);
32483
32606
  documentElement.removeAttribute(TRANSITION_TYPE_ATTRIBUTE);
32607
+ documentElement.removeAttribute(TRANSITION_COVERED_ATTRIBUTE);
32484
32608
  documentElement.removeAttribute(TRANSITION_TARGET_ATTRIBUTE);
32485
32609
  releaseTransitionWindow(transition);
32486
32610
  releaseTransitionDestination(transition);
@@ -33235,7 +33359,11 @@ const RouteTravel = ({
33235
33359
  // which is what the box is measured through: the two states are at the
33236
33360
  // same place in the layout without being at the same place in the window
33237
33361
  // (see transition_window.js).
33238
- holdTransitionWindow(travel, elementRef.current, stateBefore);
33362
+ // The bars stay live under the pictures for a travel: only the box is
33363
+ // photographed (see the TRAVEL_ATTRIBUTE css).
33364
+ holdTransitionWindow(travel, elementRef.current, stateBefore, {
33365
+ furnitureLive: true
33366
+ });
33239
33367
  });
33240
33368
  travel.viewTransition = viewTransition;
33241
33369
  if (scrub) {