@usero/sdk 1.1.12 → 1.1.13

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.
@@ -293,19 +293,77 @@ async function postNoteWithRetry(apiUrl, sessionId, atMs, text, logger) {
293
293
  }
294
294
 
295
295
  // src/plugins/user-test/ui.ts
296
+ var KEYBOARD_OPEN_MIN_INSET_PX = 80;
297
+ function computeKeyboardInset(innerHeight, viewportHeight, viewportOffsetTop) {
298
+ return Math.max(0, Math.round(innerHeight - (viewportHeight + viewportOffsetTop)));
299
+ }
300
+ function installKeyboardInsetWatcher(anchor) {
301
+ const viewport = window.visualViewport;
302
+ if (!viewport) return null;
303
+ let rafId = 0;
304
+ let lastInset = -1;
305
+ let resizeSeen = false;
306
+ const apply = () => {
307
+ rafId = 0;
308
+ const fromResize = resizeSeen;
309
+ resizeSeen = false;
310
+ const inset = computeKeyboardInset(window.innerHeight, viewport.height, viewport.offsetTop);
311
+ if (inset === lastInset) return;
312
+ lastInset = inset;
313
+ anchor.setAttribute("data-vv-scrolling", fromResize ? "false" : "true");
314
+ anchor.style.setProperty("--keyboard-inset", `${inset}px`);
315
+ anchor.style.setProperty("--vv-height", `${Math.round(viewport.height)}px`);
316
+ anchor.setAttribute("data-keyboard-open", inset >= KEYBOARD_OPEN_MIN_INSET_PX ? "true" : "false");
317
+ };
318
+ const schedule = () => {
319
+ if (rafId === 0) rafId = window.requestAnimationFrame(apply);
320
+ };
321
+ const onResize = () => {
322
+ resizeSeen = true;
323
+ schedule();
324
+ };
325
+ const onScroll = () => {
326
+ schedule();
327
+ };
328
+ viewport.addEventListener("resize", onResize);
329
+ viewport.addEventListener("scroll", onScroll);
330
+ resizeSeen = true;
331
+ apply();
332
+ return () => {
333
+ viewport.removeEventListener("resize", onResize);
334
+ viewport.removeEventListener("scroll", onScroll);
335
+ if (rafId !== 0) window.cancelAnimationFrame(rafId);
336
+ };
337
+ }
296
338
  function buildIndicator(host, store, callbacks) {
297
339
  const root = host.attachShadow({ mode: "open" });
298
340
  const style = document.createElement("style");
299
341
  style.textContent = `
300
342
  :host { all: initial; }
301
343
  .anchor {
344
+ /* --keyboard-inset is the height of the mobile soft keyboard, written by
345
+ the visualViewport watcher (0 when closed / unsupported). position:fixed
346
+ anchors to the LAYOUT viewport, which the keyboard does not shrink, so
347
+ without this the open keyboard covers the bar and task panel entirely. */
348
+ --keyboard-inset: 0px;
302
349
  position: fixed;
303
- bottom: calc(env(safe-area-inset-bottom, 0px) + 16px);
350
+ bottom: calc(env(safe-area-inset-bottom, 0px) + 16px + var(--keyboard-inset));
304
351
  left: 50%; transform: translateX(-50%);
305
352
  display: flex; flex-direction: column; align-items: center; gap: 8px;
306
353
  z-index: 2147483646; max-width: calc(100vw - 32px);
307
354
  font: 13px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
308
355
  color: #fff;
356
+ /* Eased only for keyboard show/hide; scroll ticks suppress it below. */
357
+ transition: bottom 0.18s ease-out;
358
+ }
359
+ /* While the visual viewport is being panned (URL bar collapse, pinch,
360
+ keyboard-driven scroll) the inset must track 1:1, animating every tick
361
+ reads as lag. The watcher flips this attribute per update source. */
362
+ .anchor[data-vv-scrolling="true"] { transition: none; }
363
+ /* Keyboard open: the keyboard covers the home-indicator zone, so the
364
+ safe-area + 16px margin is dead space. Tuck in to an 8px gap instead. */
365
+ .anchor[data-keyboard-open="true"] {
366
+ bottom: calc(var(--keyboard-inset) + 8px);
309
367
  }
310
368
  .bar {
311
369
  display: inline-flex; align-items: center; gap: 6px;
@@ -328,6 +386,16 @@ function buildIndicator(host, store, callbacks) {
328
386
  width: max-content; overflow-y: auto;
329
387
  }
330
388
  .panel[hidden] { display: none; }
389
+ /* Compact state while the keyboard is up: 60vh is measured against the
390
+ LAYOUT viewport and can exceed the visible strip above the keyboard,
391
+ clipping the instructions. Cap against the VISUAL viewport height
392
+ (--vv-height, written by the watcher) minus the bar's footprint, with a
393
+ 96px floor so at least a couple of lines stay readable and scrollable.
394
+ Slightly tighter padding to make the most of the scarce space. */
395
+ .anchor[data-keyboard-open="true"] .panel {
396
+ max-height: min(480px, max(96px, calc(var(--vv-height, 100vh) - 96px)));
397
+ padding: 10px 12px 10px 8px;
398
+ }
331
399
  .panel ol { margin: 0; padding-left: 26px; }
332
400
  .panel li { margin: 0 0 8px; }
333
401
  .panel li:last-child { margin: 0; }
@@ -763,10 +831,12 @@ function buildIndicator(host, store, callbacks) {
763
831
  .dot { animation: none; }
764
832
  .toast, .note-popover, .resume-toast { animation: none; }
765
833
  .resume-toast[data-leaving="true"] { opacity: 0; }
834
+ .anchor { transition: none; }
766
835
  }
767
836
  `;
768
837
  const anchor = document.createElement("div");
769
838
  anchor.className = "anchor";
839
+ store.keyboardWatcherCleanup = installKeyboardInsetWatcher(anchor);
770
840
  const panel = document.createElement("div");
771
841
  panel.className = "panel";
772
842
  panel.hidden = true;
@@ -1923,6 +1993,7 @@ function userTest(options = {}) {
1923
1993
  tasksPanelOpen: readTasksPanelOpen(),
1924
1994
  outsidePointerHandler: null,
1925
1995
  keydownHandler: null,
1996
+ keyboardWatcherCleanup: null,
1926
1997
  hasMicPermission: false,
1927
1998
  micAcquiring: true,
1928
1999
  micFailReason: null,
@@ -2129,6 +2200,10 @@ function userTest(options = {}) {
2129
2200
  document.removeEventListener("keydown", store.keydownHandler);
2130
2201
  store.keydownHandler = null;
2131
2202
  }
2203
+ if (store.keyboardWatcherCleanup) {
2204
+ store.keyboardWatcherCleanup();
2205
+ store.keyboardWatcherCleanup = null;
2206
+ }
2132
2207
  for (const id of store.muteToastTimers) {
2133
2208
  try {
2134
2209
  window.clearTimeout(id);
@@ -2158,6 +2233,7 @@ var __test__ = {
2158
2233
  classifyChunkResponse,
2159
2234
  handleSessionClosed,
2160
2235
  micChipState,
2236
+ computeKeyboardInset,
2161
2237
  isStreamSilent,
2162
2238
  rmsDbFromSamples,
2163
2239
  SILENCE_RMS_DB_THRESHOLD,