@jsenv/navi 0.29.404 → 0.29.406

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.
@@ -322,6 +322,8 @@ const SAFE_AREA_CSS = /* css */ `@property --navi-app-inset-top {
322
322
  --navi-fixed-bar-space-bottom: 0px;
323
323
  --navi-fixed-bar-space-left: 0px;
324
324
  --navi-keyboard-inset-bottom: env(keyboard-inset-height, 0px);
325
+ --navi-keyboard-strip-allowance: min(var(--navi-keyboard-inset-bottom),
326
+ 64px);
325
327
  --navi-app-inset-top: max(0px,
326
328
  (var(--navi-vvh) - var(--navi-app-max-height, var(--navi-vvh))) / 2);
327
329
  --navi-app-inset-bottom: calc(var(--navi-app-inset-top) + var(--navi-keyboard-inset-bottom));
@@ -338,23 +340,26 @@ const SAFE_AREA_CSS = /* css */ `@property --navi-app-inset-top {
338
340
  max(env(safe-area-inset-left), var(--navi-fixed-bar-space-left)));
339
341
  scroll-padding-top: var(--navi-safe-area-inset-top);
340
342
  scroll-padding-right: var(--navi-safe-area-inset-right);
341
- scroll-padding-bottom: var(--navi-safe-area-inset-bottom);
343
+ scroll-padding-bottom: calc(var(--navi-safe-area-inset-bottom) +
344
+ var(--navi-keyboard-strip-allowance));
342
345
  scroll-padding-left: var(--navi-safe-area-inset-left);
343
346
  }
344
347
 
345
348
  [data-navi-safe-area] {
346
349
  padding-top: var(--navi-safe-area-inset-top);
347
350
  padding-right: var(--navi-safe-area-inset-right);
348
- padding-bottom: var(--navi-safe-area-inset-bottom);
351
+ padding-bottom: calc(var(--navi-safe-area-inset-bottom) +
352
+ var(--navi-keyboard-strip-allowance));
349
353
  padding-left: var(--navi-safe-area-inset-left);
350
354
  scroll-padding-top: var(--navi-safe-area-inset-top);
351
355
  scroll-padding-right: var(--navi-safe-area-inset-right);
352
- scroll-padding-bottom: var(--navi-safe-area-inset-bottom);
356
+ scroll-padding-bottom: calc(var(--navi-safe-area-inset-bottom) +
357
+ var(--navi-keyboard-strip-allowance));
353
358
  scroll-padding-left: var(--navi-safe-area-inset-left);
354
359
  }
355
360
 
356
361
  :root:not(:has([data-navi-safe-area])):after {
357
- height: var(--navi-keyboard-inset-bottom);
362
+ height: calc(var(--navi-keyboard-inset-bottom) + var(--navi-keyboard-strip-allowance));
358
363
  content: "";
359
364
  display: block;
360
365
  }
@@ -3072,10 +3077,15 @@ const afterFirstFrame = (element) => {
3072
3077
  * bringing the focused field out from under the keyboard. A viewport that
3073
3078
  * shrinks makes the browser scroll to the field; a keyboard that merely paints
3074
3079
  * over the page leaves whatever is under it under it. So navi does that
3075
- * scroll here, and it needs two things safe_area.js provides: a
3076
- * scroll-padding-bottom that counts the keyboard in, so the scroll stops right
3077
- * above it, and room at the end of the scroller, so a field near the end of
3078
- * the page has somewhere to go.
3080
+ * scroll here, with two things safe_area.js provides: a scroll-padding-bottom
3081
+ * that counts the keyboard in, plus an allowance for the strip Chrome paints
3082
+ * above it without reporting it (--navi-keyboard-strip-allowance), which
3083
+ * bounds the band the field is brought into; and room at the end of the
3084
+ * scroller, so a field near the end of the page has somewhere to go.
3085
+ *
3086
+ * Only the arrival is navi's: once the field is in view, Chrome keeps the caret
3087
+ * there itself as typing grows a textarea, against that same
3088
+ * scroll-padding-bottom.
3079
3089
  */
3080
3090
 
3081
3091
 
@@ -3095,11 +3105,15 @@ const revealFocusedField = () => {
3095
3105
  if (!isEditableTarget(field)) {
3096
3106
  return;
3097
3107
  }
3098
- // "nearest" against a scroll-padding-bottom that counts the keyboard in
3099
- // (:root and [data-navi-safe-area], see safe_area.js): a field already clear
3100
- // of it does not move, one under it stops right above it.
3108
+ if (isInDocumentBand(field)) {
3109
+ return;
3110
+ }
3111
+ // "center" rather than "nearest": nearest stops the field on the band's
3112
+ // edge, clear of the strip only by the allowance. The middle of the band
3113
+ // clears a strip taller than guessed too — and centering what is not fully
3114
+ // visible is what Chrome does itself when the viewport shrinks.
3101
3115
  scrollIntoViewThroughScrollables(field, {
3102
- block: "nearest",
3116
+ block: "center",
3103
3117
  behavior: "instant",
3104
3118
  });
3105
3119
  };
@@ -3109,6 +3123,21 @@ subscribeVirtualKeyboardGeometryChange(revealFocusedField);
3109
3123
  // keyboard it does not move, and no geometrychange fires.
3110
3124
  document.addEventListener("focusin", revealFocusedField, { capture: true });
3111
3125
 
3126
+ // The band the document leaves visible: inside its scroll-padding (the bars,
3127
+ // the keyboard and its strip, see safe_area.js). Against the window rather
3128
+ // than each scroller's own band: the keyboard covers the window, and a field
3129
+ // hidden inside its own scroller is what the browser's focus already scrolls
3130
+ // to.
3131
+ const isInDocumentBand = (field) => {
3132
+ const documentElement = document.documentElement;
3133
+ const style = getComputedStyle(documentElement);
3134
+ const bandTop = parseFloat(style.scrollPaddingTop) || 0;
3135
+ const bandBottom =
3136
+ documentElement.clientHeight - (parseFloat(style.scrollPaddingBottom) || 0);
3137
+ const { top, bottom } = field.getBoundingClientRect();
3138
+ return top >= bandTop && bottom <= bandBottom;
3139
+ };
3140
+
3112
3141
  installImportMetaCssBuild(import.meta);
3113
3142
 
3114
3143
  const button = document.createElement("button");