@jsenv/navi 0.29.347 → 0.29.349

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.
@@ -172,7 +172,9 @@ to start when unsure which export solves a problem.
172
172
  - `popup_lift.md` — `animation="lifting"`: the pressed card brought to the
173
173
  front. `data-lift` names what is lifted and is rendered at once; the
174
174
  trigger's box is the card's box; `lift="box"` for a card, `"scene"` for a
175
- drawing framed the same way; what an opening costs and where the time goes;
175
+ drawing framed the same way; one popup for a whole row, walked from the front
176
+ through a `SlideContainer`, `liftAnchor` naming where the closing comes back
177
+ to; what an opening costs and where the time goes;
176
178
  the wall at half strength on the frame before the movement. Read before
177
179
  giving a `Dialog` or a `Picker` `animation="lifting"`, or before measuring
178
180
  why one opens slowly.
@@ -18,6 +18,7 @@ and everything below follows from that one fact.
18
18
  - [Two kinds: a card, or a scene](#two-kinds-a-card-or-a-scene)
19
19
  - [The lifted node paints itself](#the-lifted-node-paints-itself)
20
20
  - [Same width, or a wider box](#same-width-or-a-wider-box)
21
+ - [A row of cards: one popup that walks](#a-row-of-cards-one-popup-that-walks)
21
22
  - [What it costs, and where the time goes](#what-it-costs-and-where-the-time-goes)
22
23
  - [The wall, and the frame before the movement](#the-wall-and-the-frame-before-the-movement)
23
24
  - [What the browser does around it](#what-the-browser-does-around-it)
@@ -38,6 +39,10 @@ lifts the card; a dialog that is the card wears `data-lift` itself.
38
39
  </Picker>
39
40
  ```
40
41
 
42
+ That names one end. The other is the anchor — the box the opening came out of,
43
+ and the box the closing goes back into unless `liftAnchor` names another (see
44
+ [a row of cards](#a-row-of-cards-one-popup-that-walks)).
45
+
41
46
  The opening waits for it. What a popup holds often arrives after the tap —
42
47
  code fetched for the address, a row fetched for the popup — and a movement
43
48
  started before the lifted node exists would carry the card into an empty box.
@@ -128,6 +133,118 @@ gaining room on the right, then the wider layout arrives.
128
133
  Both read well; what does not is a box that is neither: a card whose width the
129
134
  sheet changes by a few pixels for no reason the eye can name. Decide.
130
135
 
136
+ ## A row of cards: one popup that walks
137
+
138
+ A row of small drawings — trophies on a profile, photos, badges — where
139
+ pressing one brings it to the front, big, and from there the next one is
140
+ reached without going back to the row. The popup is then about the whole row,
141
+ and the press only says where it opens: one `Dialog` for the row, lifting,
142
+ holding a `SlideContainer` the walk moves through.
143
+
144
+ ```jsx
145
+ const currentKeySignal = useSignal(undefined);
146
+
147
+ <Button
148
+ id={`cup_tile_${cup.key}`}
149
+ command="--navi-open"
150
+ commandFor={ZOOM_ID}
151
+ value={cup.key}
152
+ variant="bare"
153
+ >
154
+ <Trophy medal={cup.medal} />
155
+ </Button>
156
+
157
+ <Dialog
158
+ id={ZOOM_ID}
159
+ animation="lifting"
160
+ mount="while-opened"
161
+ onOpen={(e) => {
162
+ currentKeySignal.value = e.detail.value;
163
+ }}
164
+ liftAnchor={`cup_tile_${currentKeySignal.value}`}
165
+ expand
166
+ data-slide-container-follows={SLIDES_ID}
167
+ >
168
+ <SlideContainer id={SLIDES_ID} signal={currentKeySignal} expandY>
169
+ {cups.map((cup) => (
170
+ <Slide key={cup.key} area={cup.key}>
171
+ <Box data-lift={cup.key === currentKeySignal.value ? "" : undefined}>
172
+ <Trophy medal={cup.medal} size="min(46vw, 180px)" />
173
+ </Box>
174
+ <Circumstances cup={cup} />
175
+ </Slide>
176
+ ))}
177
+ </SlideContainer>
178
+ <SlideContainer.Left commandFor={SLIDES_ID} />
179
+ <SlideContainer.Right commandFor={SLIDES_ID} />
180
+ </Dialog>
181
+ ```
182
+
183
+ **One popup, because the popup is about the row.** A picker per drawing is the
184
+ first thing one writes, and it is a dead end: each popup would have to hold the
185
+ whole row to be walkable, so a row of N costs N×N slides, and a walk opened on
186
+ the second drawing ends in a popup whose trigger is somewhere else. That is a
187
+ reason of its own to share a popup, beside the two in
188
+ [popup_open.md](./popup_open.md#when-a-shared-popup-is-still-the-right-answer):
189
+ what the popup shows is more than what was pressed.
190
+
191
+ **Which drawing it opens on is the command's `value`.** The press says it the
192
+ way it says it everywhere ([opening it ON
193
+ something](./popup_open.md#opening-it-on-something)), and `onOpen` writes it
194
+ into the container's own signal — the press seeds the walk rather than keeping
195
+ a second copy of it, and from then on the chevrons, the arrows and a thumb
196
+ write the same signal (see [state_binding.md](./state_binding.md)).
197
+
198
+ **`data-lift` moves with the walk, and has to be right on the first frame.**
199
+ There is one lifted node per document, and here it is the current slide's
200
+ drawing — a condition on the signal, not a mark written once on the popup. The
201
+ lift takes the first `data-lift` it finds on the frame the popup opens:
202
+ `mount="while-opened"` is what makes that frame the right one, since the
203
+ content is built after `onOpen`, on the drawing the open named. Content kept
204
+ across openings still carries the mark of the drawing the walk was left on, and
205
+ the lift takes that one. The closing reads it the same way, and a mark left on
206
+ a slide the walk moved off is a picture taken where that slide stands — off
207
+ screen — so the box flies in from outside the surface. The bill for rebuilding
208
+ is the row's, not one card's — every slide is built on every opening (see
209
+ [costs](#what-it-costs-and-where-the-time-goes)).
210
+
211
+ **The trigger's box is what travels, so the button is the drawing and nothing
212
+ else.** That is [the trigger's box is the card's
213
+ box](#the-triggers-box-is-the-cards-box) read backwards: everything inside the
214
+ button is stretched into the popup's box on the way. A tile is usually more
215
+ than its drawing — a count floating in a corner, a level written
216
+ underneath — and those belong outside the button, positioned against the tile
217
+ or placed under it. Layout, not a prop.
218
+
219
+ **The anchor comes with the press.** A button opening a popup names itself as
220
+ the anchor ([the anchor](./popup_open.md#the-anchor), third rule), so the lift
221
+ starts on the drawing that was pressed, with no `anchor` prop and no
222
+ `triggerNaviCommand`. Writing an `anchor` prop is how to lose that: the prop is
223
+ what answers when no press does, and it wins over the press.
224
+
225
+ **The arrows reach the walk from anywhere on the surface.** Only slides go in a
226
+ `SlideContainer`, so the chevrons pinned to the edges of a full-screen surface
227
+ are outside it, and the keyboard, once it lands on one of them, walks nothing.
228
+ `data-slide-container-follows={SLIDES_ID}` on the `Dialog` — the outermost
229
+ element, which is what holds the keyboard when nothing in it does — makes the
230
+ whole surface a follower.
231
+
232
+ **Where it comes back to is named too.** The opening's anchor is the drawing
233
+ that was pressed, and a walk that moved on has something else in front by the
234
+ time it closes: left alone, the silver cup flies home into the gold cup's
235
+ tile. `liftAnchor` says the other end — same grammar as `anchor` (element, ref
236
+ or id), read at the close rather than kept from the opening, so what names the
237
+ tile currently in front is read then. An id built from the signal the walk is
238
+ bound to is the shortest way to say it, the row's tiles carrying the matching
239
+ ids. Left out, the box comes back where it came from, which is right exactly
240
+ as long as nothing walked.
241
+
242
+ **A press on the surface that dismisses is `data-navi-popup-outside`.** Marking
243
+ the see-through box as backdrop (see
244
+ [popup_backdrop.md](./popup_backdrop.md)) is read on the press itself. A close
245
+ written by hand on a click has to tell a click from the end of a swipe — and
246
+ that guard is the sign the marker was missed.
247
+
131
248
  ## What it costs, and where the time goes
132
249
 
133
250
  Measured at CPU ×6 on the demo bench (`12_picker_card_demo.html#lift-bench`),
@@ -147,7 +264,9 @@ hot spot, plus `showModal()` and one layout. So the lever is the content:
147
264
 
148
265
  - **Build less, or earlier.** A sheet that is the same across openings keeps
149
266
  `mount="from-first-open"`. A sheet that must be rebuilt (`while-opened`)
150
- pays its build on every tap; keep it as light as the page allows.
267
+ pays its build on every tap; keep it as light as the page allows. A popup
268
+ whose lifted node changes from one opening to the next has no choice — see
269
+ [a row of cards](#a-row-of-cards-one-popup-that-walks).
151
270
  - **Do not rebuild by accident.** A sheet whose code or data is tied to the
152
271
  address (`?edit=<id>` driving a route action) is thrown away when the
153
272
  address clears and rebuilt through a `null` render on the next opening —
@@ -585,15 +585,19 @@ frame it would cover it, and every press on the empty plan would open it.
585
585
 
586
586
  ### When a shared popup is still the right answer
587
587
 
588
- Two cases, and only two:
588
+ Three cases, and only three:
589
589
 
590
590
  - **the press can come from anywhere** — a keyboard shortcut, a menu, a button,
591
591
  all opening the same thing. Written per press it would exist several times
592
592
  over, each with its own open state;
593
593
  - **the popup has to outlive its trigger** — a row that leaves while its dialog
594
- is open (a list refreshing under it) takes a popup written inside it with it.
594
+ is open (a list refreshing under it) takes a popup written inside it with it;
595
+ - **the popup is about more than what was pressed** — a viewer one walks
596
+ through, where the press only says which item it opens on. Written per item,
597
+ each popup would have to hold the whole row to be walkable. See
598
+ [popup_lift.md](./popup_lift.md#a-row-of-cards-one-popup-that-walks).
595
599
 
596
- Neither is "one popup per row of a list", which is what a picker is for.
600
+ None of them is "one popup per row of a list", which is what a picker is for.
597
601
 
598
602
  Do not mix the two. A `<Form>` at the root of a picker's popup IS the mirrored
599
603
  control, so its value is the picker's value: handing the picker something else
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/navi",
3
- "version": "0.29.347",
3
+ "version": "0.29.349",
4
4
  "type": "module",
5
5
  "description": "Library of components including navigation to create frontend applications",
6
6
  "repository": {