@jsenv/navi 0.29.372 → 0.29.374

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.
@@ -30029,6 +30029,11 @@ const FURNITURE_NAME_PREFIX = "navi-transition-furniture-";
30029
30029
  const TOP_LAYER_WALL_SELECTOR =
30030
30030
  ".navi_dialog:modal, .navi_popover_backdrop:popover-open";
30031
30031
  const WALL_ATTRIBUTE = "data-navi-transition-wall";
30032
+ // Worn by a bar both states have, from the hold on: its two pictures are one
30033
+ // group, and the group is ordered over the pages (route_transition.jsx). Only
30034
+ // a bar — a popup's class is written by layout/popup_css.js, and a second rule
30035
+ // on the same property would replace it.
30036
+ const SHARED_ATTRIBUTE = "data-navi-transition-furniture-shared";
30032
30037
  // What the wall paints, resolved on the matched element in both cases (the
30033
30038
  // dialog for its ::backdrop, the popover's wall for itself): the same two
30034
30039
  // properties, copied onto the stand-in.
@@ -30037,7 +30042,11 @@ const WALL_PROPERTIES = ["--backdrop-background", "--backdrop-filter"];
30037
30042
  // The pictures the wall is painted into: the pages', and every bar's own.
30038
30043
  const FIXED_BAR_SELECTOR$1 = ".navi_fixed_bar";
30039
30044
 
30040
- const TRANSITION_WALL_CSS = /* css */ `[data-navi-transition-wall] {
30045
+ const TRANSITION_FURNITURE_CSS = /* css */ `.navi_fixed_bar[data-navi-transition-furniture-shared] {
30046
+ view-transition-class: navi_furniture_shared;
30047
+ }
30048
+
30049
+ [data-navi-transition-wall] {
30041
30050
  z-index: var(--navi-z-index-top-layer);
30042
30051
  background: var(--backdrop-background);
30043
30052
  backdrop-filter: var(--backdrop-filter);
@@ -30070,7 +30079,7 @@ const TRANSITION_WALL_CSS = /* css */ `[data-navi-transition-wall] {
30070
30079
  // a page that never travels between routes must not carry this sheet, and a
30071
30080
  // build that sees no caller drops the css with the function.
30072
30081
  const installTransitionFurnitureCss = () => {
30073
- import.meta.css = [TRANSITION_WALL_CSS, "@jsenv/navi/src/nav/transition_furniture.js"];
30082
+ import.meta.css = [TRANSITION_FURNITURE_CSS, "@jsenv/navi/src/nav/transition_furniture.js"];
30074
30083
  };
30075
30084
 
30076
30085
  const nameByElement = new WeakMap();
@@ -30132,6 +30141,8 @@ const holdTransitionFurniture = (owner, areaElement) => {
30132
30141
  for (const element of namedElements) {
30133
30142
  if (!element.isConnected) {
30134
30143
  namesLeaving.push(nameByElement.get(element));
30144
+ } else if (element.matches(FIXED_BAR_SELECTOR$1)) {
30145
+ element.setAttribute(SHARED_ATTRIBUTE, "");
30135
30146
  }
30136
30147
  }
30137
30148
  const namesArriving = nameFurnitureAround(areaElement);
@@ -30262,6 +30273,7 @@ const releaseTransitionFurniture = (owner) => {
30262
30273
  furnitureOwner = null;
30263
30274
  for (const element of namedElements) {
30264
30275
  element.style.removeProperty(NAME_PROPERTY$1);
30276
+ element.removeAttribute(SHARED_ATTRIBUTE);
30265
30277
  }
30266
30278
  namedElements = new Set();
30267
30279
  if (travelStyleElement) {
@@ -30293,12 +30305,12 @@ const paintTransitionWalls = (areaElement) => {
30293
30305
  // positioned against an ancestor of it: the wall is placed from
30294
30306
  // wherever its containing block turns out to be, by the offset between
30295
30307
  // that box and the target's.
30296
- const targetRect = target.getBoundingClientRect();
30308
+ const targetRect = pictureRect(target);
30297
30309
  const wallRect = wall.getBoundingClientRect();
30298
30310
  wall.style.left = `${targetRect.left - wallRect.left}px`;
30299
30311
  wall.style.top = `${targetRect.top - wallRect.top}px`;
30300
- wall.style.width = `${targetRect.width}px`;
30301
- wall.style.height = `${targetRect.height}px`;
30312
+ wall.style.width = `${targetRect.right - targetRect.left}px`;
30313
+ wall.style.height = `${targetRect.bottom - targetRect.top}px`;
30302
30314
  wallElements.push(wall);
30303
30315
  }
30304
30316
  }
@@ -30352,11 +30364,45 @@ const paintRestWalls = (sources, opacity) => {
30352
30364
  const measurePictureRects = (areaElement) => {
30353
30365
  const rects = new Map();
30354
30366
  for (const target of pictureTargets(areaElement)) {
30355
- rects.set(target, target.getBoundingClientRect());
30367
+ rects.set(target, pictureRect(target));
30356
30368
  }
30357
30369
  return rects;
30358
30370
  };
30359
30371
 
30372
+ // What the picture holds, which is what the wall covers at rest: a bar's
30373
+ // picture carries what its content paints outside its box (a button standing
30374
+ // up out of a tab bar), so its rectangle is taken with its descendants'. The
30375
+ // pages' is their own box — the movement cuts them at it anyway.
30376
+ const pictureRect = (target) => {
30377
+ const rect = target.getBoundingClientRect();
30378
+ let { left, top, right, bottom } = rect;
30379
+ if (!target.matches(FIXED_BAR_SELECTOR$1)) {
30380
+ return { left, top, right, bottom };
30381
+ }
30382
+ for (const descendant of target.querySelectorAll("*")) {
30383
+ if (descendant.hasAttribute(WALL_ATTRIBUTE)) {
30384
+ continue;
30385
+ }
30386
+ const descendantRect = descendant.getBoundingClientRect();
30387
+ if (descendantRect.width === 0 || descendantRect.height === 0) {
30388
+ continue;
30389
+ }
30390
+ if (descendantRect.left < left) {
30391
+ left = descendantRect.left;
30392
+ }
30393
+ if (descendantRect.top < top) {
30394
+ top = descendantRect.top;
30395
+ }
30396
+ if (descendantRect.right > right) {
30397
+ right = descendantRect.right;
30398
+ }
30399
+ if (descendantRect.bottom > bottom) {
30400
+ bottom = descendantRect.bottom;
30401
+ }
30402
+ }
30403
+ return { left, top, right, bottom };
30404
+ };
30405
+
30360
30406
  // The holes for the movement, and the ones for its last frame (see the CSS).
30361
30407
  const cutRestWalls = (holes, holesArriving = null) => {
30362
30408
  for (const restWall of restWallElements) {
@@ -30371,15 +30417,83 @@ const cutRestWalls = (holes, holesArriving = null) => {
30371
30417
  };
30372
30418
 
30373
30419
  // One evenodd polygon: the window, then each hole entered from and left by
30374
- // the window's origin, so the bridges between them have no area.
30420
+ // the window's origin, so the bridges between them have no area. The holes
30421
+ // must not overlap — evenodd fills where two of them do — and they do
30422
+ // overlap as measured: the pages run under the bars by design, so a bar's
30423
+ // rectangle lies inside the area's. Each is cut down to what the ones before
30424
+ // it left.
30375
30425
  const holesPolygon = (holes) => {
30376
30426
  let polygon = "0 0, 100% 0, 100% 100%, 0 100%, 0 0";
30377
- for (const { left, top, right, bottom } of holes) {
30427
+ for (const { left, top, right, bottom } of disjointRects(holes)) {
30378
30428
  polygon += `, ${left}px ${top}px, ${right}px ${top}px, ${right}px ${bottom}px, ${left}px ${bottom}px, ${left}px ${top}px, 0 0`;
30379
30429
  }
30380
30430
  return `polygon(evenodd, ${polygon})`;
30381
30431
  };
30382
30432
 
30433
+ const disjointRects = (rects) => {
30434
+ const result = [];
30435
+ for (const rect of rects) {
30436
+ let pieces = [rect];
30437
+ for (const placed of result) {
30438
+ const remaining = [];
30439
+ for (const piece of pieces) {
30440
+ remaining.push(...subtractRect(piece, placed));
30441
+ }
30442
+ pieces = remaining;
30443
+ }
30444
+ result.push(...pieces);
30445
+ }
30446
+ return result;
30447
+ };
30448
+
30449
+ // What is left of `rect` outside `hole`: up to four rectangles around it.
30450
+ const subtractRect = (rect, hole) => {
30451
+ if (
30452
+ hole.left >= rect.right ||
30453
+ hole.right <= rect.left ||
30454
+ hole.top >= rect.bottom ||
30455
+ hole.bottom <= rect.top
30456
+ ) {
30457
+ return [rect];
30458
+ }
30459
+ const pieces = [];
30460
+ const innerTop = hole.top > rect.top ? hole.top : rect.top;
30461
+ const innerBottom = hole.bottom < rect.bottom ? hole.bottom : rect.bottom;
30462
+ if (hole.top > rect.top) {
30463
+ pieces.push({
30464
+ left: rect.left,
30465
+ top: rect.top,
30466
+ right: rect.right,
30467
+ bottom: hole.top,
30468
+ });
30469
+ }
30470
+ if (hole.bottom < rect.bottom) {
30471
+ pieces.push({
30472
+ left: rect.left,
30473
+ top: hole.bottom,
30474
+ right: rect.right,
30475
+ bottom: rect.bottom,
30476
+ });
30477
+ }
30478
+ if (hole.left > rect.left) {
30479
+ pieces.push({
30480
+ left: rect.left,
30481
+ top: innerTop,
30482
+ right: hole.left,
30483
+ bottom: innerBottom,
30484
+ });
30485
+ }
30486
+ if (hole.right < rect.right) {
30487
+ pieces.push({
30488
+ left: hole.right,
30489
+ top: innerTop,
30490
+ right: rect.right,
30491
+ bottom: innerBottom,
30492
+ });
30493
+ }
30494
+ return pieces;
30495
+ };
30496
+
30383
30497
  const removeRestWalls = () => {
30384
30498
  for (const restWall of restWallElements) {
30385
30499
  restWall.remove();
@@ -30964,10 +31078,14 @@ const css$12 = /* css */`:root[data-navi-route-transition] [data-navi-route-tran
30964
31078
  z-index: 1;
30965
31079
  }
30966
31080
 
30967
- &::view-transition-group(.navi_popup) {
31081
+ &::view-transition-group(.navi_furniture_shared) {
30968
31082
  z-index: 2;
30969
31083
  }
30970
31084
 
31085
+ &::view-transition-group(.navi_popup) {
31086
+ z-index: 3;
31087
+ }
31088
+
30971
31089
  &::view-transition-group(*), &::view-transition-old(*), &::view-transition-new(*) {
30972
31090
  animation-duration: var(--navi-route-transition-duration, .3s);
30973
31091
  }