@jsenv/navi 0.29.428 → 0.29.430

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.
@@ -30911,14 +30911,14 @@ import.meta.css = /* css */[`[data-scrollable] > .navi_loading_outline_wrapper,
30911
30911
  }
30912
30912
 
30913
30913
  [data-scrollable] {
30914
- overflow: var(--x-scrollable-overflow, auto);
30915
30914
  scroll-padding: var(--navi-scroll-padding, var(--navi-s));
30916
30915
  --box-header-z-index: var(--navi-z-index-sticky);
30917
30916
  --box-footer-z-index: var(--navi-z-index-sticky);
30918
30917
  isolation: isolate;
30918
+ overflow: auto;
30919
30919
 
30920
30920
  &[data-scrollable-overflow="scroll"] {
30921
- --x-scrollable-overflow: scroll;
30921
+ overflow: scroll;
30922
30922
  }
30923
30923
 
30924
30924
  & > [data-header] {
@@ -30940,9 +30940,9 @@ import.meta.css = /* css */[`[data-scrollable] > .navi_loading_outline_wrapper,
30940
30940
  }
30941
30941
 
30942
30942
  &:has( > [data-body]) {
30943
- --x-scrollable-overflow: hidden;
30944
30943
  flex-direction: column;
30945
30944
  display: flex;
30945
+ overflow: hidden;
30946
30946
 
30947
30947
  & > [data-header], & > [data-footer] {
30948
30948
  z-index: auto;
@@ -39814,6 +39814,16 @@ const resolveAfterSend = (target, requester) => {
39814
39814
  }
39815
39815
  return undefined;
39816
39816
  };
39817
+ // What follows a send is caused by the send, not by the gesture: the send
39818
+ // answered the gesture and may have prevented it (an Enter must not also click
39819
+ // the submit button, nor activate the trigger of the popup it closed), and a
39820
+ // follow-up judged on that event is refused as a gesture someone cancelled.
39821
+ // Chained, so the gesture stays readable behind it.
39822
+ const createSentEvent = (event) => {
39823
+ const sentEvent = new CustomEvent("sent", { detail: {} });
39824
+ chainEvent(sentEvent, event);
39825
+ return sentEvent;
39826
+ };
39817
39827
 
39818
39828
  registerNaviCommand("--navi-send", (source, event, { requester }) => {
39819
39829
  const expandable = resolveExpandableAround(source);
@@ -39846,7 +39856,9 @@ registerNaviCommand("--navi-send", (source, event, { requester }) => {
39846
39856
  source.getAttribute("data-after-send") ||
39847
39857
  target.getAttribute("data-after-send");
39848
39858
  if (afterSend) {
39849
- triggerNaviCommand(target, afterSend, event, { optional: true });
39859
+ triggerNaviCommand(target, afterSend, createSentEvent(event), {
39860
+ optional: true,
39861
+ });
39850
39862
  }
39851
39863
  return result;
39852
39864
  },
@@ -39890,7 +39902,9 @@ registerNaviCommand("--navi-send", (source, event, { requester }) => {
39890
39902
  if (!afterSend) {
39891
39903
  return;
39892
39904
  }
39893
- triggerNaviCommand(source, afterSend, event, { optional: true });
39905
+ triggerNaviCommand(source, afterSend, createSentEvent(event), {
39906
+ optional: true,
39907
+ });
39894
39908
  };
39895
39909
  const {
39896
39910
  result: sent,
@@ -67033,7 +67047,11 @@ const useDialogProps = props => {
67033
67047
  }
67034
67048
  const anchorElement = resolveAnchorElement(event);
67035
67049
  if (!anchorElement) {
67036
- {
67050
+ // An opening by the caller's state (`open`, `signal`, `navState`) is
67051
+ // told nothing about its cause, and that cause may be the address —
67052
+ // a back to an entry where the dialog was open, nothing pressed — so
67053
+ // a missing anchor there is not something the app could have given.
67054
+ if (event.type !== "open_by_prop") {
67037
67055
  console.warn(`[navi] Dialog has animation="lifting" and no anchor to lift out of, so it simply appears. The anchor is whatever opened it — a <Button command="--navi-open">, the "source" given to triggerNaviCommand — or the "anchor" prop.`);
67038
67056
  }
67039
67057
  applyChange();
@@ -74111,9 +74129,12 @@ const useListScrollSync = ({
74111
74129
  };
74112
74130
  const [renderWindow, setRenderWindow] = useState(() => {
74113
74131
  // Opening somewhere else than the beginning starts by framing there: the
74114
- // items the list will draw are the items it will ask for.
74132
+ // items the list will draw are the items it will ask for. A named item is
74133
+ // framed where it stood when it was written down, which is where holdWindow
74134
+ // aims before anyone can say where it is.
74115
74135
  const openAt = scrolled ?? defaultScrolled;
74116
- const start = typeof openAt === "number" ? openAt - itemsAboveOpening(openAt, firstWindowItemCount) : 0;
74136
+ const openIndex = typeof openAt === "number" ? openAt : openAt && typeof openAt === "object" && typeof openAt.index === "number" ? openAt.index : null;
74137
+ const start = openIndex === null ? 0 : openIndex - itemsAboveOpening(openAt, firstWindowItemCount);
74117
74138
  const startClamped = start < 0 ? 0 : start;
74118
74139
  return {
74119
74140
  start: startClamped,
@@ -74240,14 +74261,11 @@ const useListScrollSync = ({
74240
74261
  if (wantedStart < 0) {
74241
74262
  wantedStart = 0;
74242
74263
  }
74243
- if (wantedStart === start) {
74244
- listItems.holdPending = false;
74245
- return;
74246
- }
74247
- renderWindowRef.current = {
74248
- start: wantedStart,
74249
- end: wantedStart + windowSize
74250
- };
74264
+ // The window the hold frames goes into the state, not into this render
74265
+ // alone: the next render starts from the state, and once the item stands
74266
+ // inside the window the hold stops framing it — a window left where the
74267
+ // state had it would draw around another place.
74268
+ updateRenderWindow(wantedStart, wantedStart + windowSize, `held on item ${heldItem}`);
74251
74269
  listItems.holdPending = false;
74252
74270
  };
74253
74271
  const pendingScrollRef = useRef();
@@ -74396,6 +74414,13 @@ const useListScrollSync = ({
74396
74414
  return;
74397
74415
  }
74398
74416
  hasBeenDisplayedRef.current = true;
74417
+ const place = startPlaceRef.current;
74418
+ if (!place.userTookOver && place.wanted !== "start" && place.wanted !== undefined) {
74419
+ // Held somewhere: where the list opens is the hold's to say (see
74420
+ // placeWhereHeld). Scrolled here too, the list would go to the top or
74421
+ // the selected item for as long as the hold takes to put it back.
74422
+ return;
74423
+ }
74399
74424
  const items = listItems.itemsSignal.peek();
74400
74425
  const firstSelected = items.find(i => {
74401
74426
  if (i.selected) {
@@ -75098,12 +75123,14 @@ const useListScrollSync = ({
75098
75123
  const spare = budget > screen ? budget - screen : 0;
75099
75124
  const behindSize = countsItems ? Math.floor(spare / 4) : spare / 4;
75100
75125
  const aheadSize = spare - behindSize;
75101
- if (stage === "steady" && !budgetWarnedRef.current && bandEnd > bandStart) {
75102
- const twoLines = (countsItems ? 2 : 2 * (bandTo - bandFrom) / (bandEnd - bandStart)) * itemsPerLineNow;
75103
- if (spare < twoLines) {
75104
- budgetWarnedRef.current = true;
75105
- console.warn(`List: renderBudget=${renderBudget.value}${renderBudget.unit} leaves less than two ${itemsPerLineNow > 1 ? "lines of items" : "items"} beyond what the screen shows (${bandEnd - bandStart} items): items will go blank as it scrolls. Give it room for a screen ahead or more — "300%" of the box that scrolls it, say.`);
75106
- }
75126
+ // Said only when the budget holds nothing past the screen: the blank is
75127
+ // then certain. Past the screen, whether a fling outruns the window is
75128
+ // what the device and the rest of the main thread's work decide, and a
75129
+ // number of items cannot tell it — two one-line items are 76 px, two
75130
+ // cards a whole screen. That is measured on the list, not guessed here.
75131
+ if (stage === "steady" && !budgetWarnedRef.current && bandEnd > bandStart && spare === 0) {
75132
+ budgetWarnedRef.current = true;
75133
+ console.warn(`List: renderBudget=${renderBudget.value}${renderBudget.unit} holds no more than what the screen shows (${bandEnd - bandStart} items on it): the screen goes blank past it as soon as the list scrolls. Give it more than a screen — "150%" of the box that scrolls it, say.`);
75107
75134
  }
75108
75135
  if (!force) {
75109
75136
  const roomAround = readRoomAround({
@@ -78798,7 +78825,8 @@ const ListResolved = /*#__PURE__*/createComponentResolver([ListFirstResolver, Li
78798
78825
  * "Many rows"). The window keeps three quarters of what the screen leaves of
78799
78826
  * it ahead of the scroll, and moves once that falls under half a screen; it
78800
78827
  * has to hold more than the screen shows, with room for that lookahead — the
78801
- * list warns when it leaves less than two items beyond the screen.
78828
+ * list warns when it holds no more than the screen. How much more is
78829
+ * measured: fling the list on the slowest device it runs on.
78802
78830
  *
78803
78831
  * `{ initial, after }` for a list whose first picture is taken as it is
78804
78832
  * built — drawn in the click that opens a popup, or in the update callback