@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
  }
@@ -3160,10 +3165,15 @@ const pollInDev = (check) => {
3160
3165
  * bringing the focused field out from under the keyboard. A viewport that
3161
3166
  * shrinks makes the browser scroll to the field; a keyboard that merely paints
3162
3167
  * over the page leaves whatever is under it under it. So navi does that
3163
- * scroll here, and it needs two things safe_area.js provides: a
3164
- * scroll-padding-bottom that counts the keyboard in, so the scroll stops right
3165
- * above it, and room at the end of the scroller, so a field near the end of
3166
- * the page has somewhere to go.
3168
+ * scroll here, with two things safe_area.js provides: a scroll-padding-bottom
3169
+ * that counts the keyboard in, plus an allowance for the strip Chrome paints
3170
+ * above it without reporting it (--navi-keyboard-strip-allowance), which
3171
+ * bounds the band the field is brought into; and room at the end of the
3172
+ * scroller, so a field near the end of the page has somewhere to go.
3173
+ *
3174
+ * Only the arrival is navi's: once the field is in view, Chrome keeps the caret
3175
+ * there itself as typing grows a textarea, against that same
3176
+ * scroll-padding-bottom.
3167
3177
  */
3168
3178
 
3169
3179
 
@@ -3183,11 +3193,15 @@ const revealFocusedField = () => {
3183
3193
  if (!isEditableTarget(field)) {
3184
3194
  return;
3185
3195
  }
3186
- // "nearest" against a scroll-padding-bottom that counts the keyboard in
3187
- // (:root and [data-navi-safe-area], see safe_area.js): a field already clear
3188
- // of it does not move, one under it stops right above it.
3196
+ if (isInDocumentBand(field)) {
3197
+ return;
3198
+ }
3199
+ // "center" rather than "nearest": nearest stops the field on the band's
3200
+ // edge, clear of the strip only by the allowance. The middle of the band
3201
+ // clears a strip taller than guessed too — and centering what is not fully
3202
+ // visible is what Chrome does itself when the viewport shrinks.
3189
3203
  scrollIntoViewThroughScrollables(field, {
3190
- block: "nearest",
3204
+ block: "center",
3191
3205
  behavior: "instant",
3192
3206
  });
3193
3207
  };
@@ -3197,6 +3211,21 @@ subscribeVirtualKeyboardGeometryChange(revealFocusedField);
3197
3211
  // keyboard it does not move, and no geometrychange fires.
3198
3212
  document.addEventListener("focusin", revealFocusedField, { capture: true });
3199
3213
 
3214
+ // The band the document leaves visible: inside its scroll-padding (the bars,
3215
+ // the keyboard and its strip, see safe_area.js). Against the window rather
3216
+ // than each scroller's own band: the keyboard covers the window, and a field
3217
+ // hidden inside its own scroller is what the browser's focus already scrolls
3218
+ // to.
3219
+ const isInDocumentBand = (field) => {
3220
+ const documentElement = document.documentElement;
3221
+ const style = getComputedStyle(documentElement);
3222
+ const bandTop = parseFloat(style.scrollPaddingTop) || 0;
3223
+ const bandBottom =
3224
+ documentElement.clientHeight - (parseFloat(style.scrollPaddingBottom) || 0);
3225
+ const { top, bottom } = field.getBoundingClientRect();
3226
+ return top >= bandTop && bottom <= bandBottom;
3227
+ };
3228
+
3200
3229
  installImportMetaCssBuild(import.meta);
3201
3230
 
3202
3231
  const button = document.createElement("button");