@jsenv/navi 0.29.389 → 0.29.391
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.
- package/dist/dev/jsenv_navi.js +376 -135
- package/dist/dev/jsenv_navi.js.map +8 -8
- package/dist/jsenv_navi.js +376 -135
- package/dist/jsenv_navi.js.map +8 -8
- package/docs/drag_interactions.md +13 -5
- package/docs/pan_zoom.md +11 -4
- package/docs/resource.md +45 -1
- package/package.json +2 -2
|
@@ -373,11 +373,19 @@ copy where the hand put it, over the thing appearing there.
|
|
|
373
373
|
#### Naming what travels
|
|
374
374
|
|
|
375
375
|
**The copy is already named, and it is the copy that does the visible travel.**
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
376
|
+
`syncCloneWithDropTarget` moves it onto the destination inside the callback — so
|
|
377
|
+
the piece the hand let go of slides to its place whether the application names
|
|
378
|
+
anything or not. What is left to name is the OTHER one: the piece that was
|
|
379
|
+
standing there and has to go the other way.
|
|
380
|
+
|
|
381
|
+
The name is the copy's own, because two copies can be on screen at once — one
|
|
382
|
+
still flying away while its `toss` is answered, another landing — and a name
|
|
383
|
+
claimed twice aborts the transition. What every copy shares is the class
|
|
384
|
+
`navi-drag-clone`, which is how a stylesheet reaches the landing:
|
|
385
|
+
`::view-transition-group(.navi-drag-clone)`. A view-transition class is read
|
|
386
|
+
from Chrome 125 on; before that the landing still plays, and only a rule written
|
|
387
|
+
against the class goes unread. The wrapper carrying the copy paints nothing and
|
|
388
|
+
takes neither.
|
|
381
389
|
|
|
382
390
|
**And the original is hidden for the whole landing**, not only for the drag: it
|
|
383
391
|
wears `navi-drag-clone-source` (`visibility: hidden`) until the promise returned
|
package/docs/pan_zoom.md
CHANGED
|
@@ -42,14 +42,21 @@ when it lands; the pan stepping back for what is carried across the surface (a
|
|
|
42
42
|
`move`, a handle, a field, a popover — the same list a travelling box steps back
|
|
43
43
|
for); the pinch not beginning as a pan under its first finger; the wheel and the
|
|
44
44
|
pinch writing one `zoom`; the capture, the pointer the browser drops, the click
|
|
45
|
-
the release leaves behind
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
the release leaves behind, and the next tap's click, which Chrome on Android
|
|
46
|
+
drops after a touch drag whose `touchmove`s nobody refused (see
|
|
47
|
+
[mobile_tap_suppression_after_drag.md](./mobile_tap_suppression_after_drag.md)).
|
|
48
|
+
A pointer pans only once it has travelled a few px (`data-drag-threshold`), so a
|
|
49
|
+
tap stays a tap: a `longpress` declared beside `pan` still gets its hold, and a
|
|
50
|
+
`double_click` still gets its two presses. A press that does pan is the
|
|
51
|
+
surface's: a `longpress` waiting on it gives up the moment the pan begins, even
|
|
52
|
+
inside its own slop.
|
|
48
53
|
|
|
49
54
|
Declared alone, `zoom` takes two fingers and the wheel and leaves one pointer to
|
|
50
55
|
whatever else reads it: nothing captures it, waits on it or swallows its click
|
|
51
56
|
until a second finger lands, so a `click` or a `longpress` declared beside `zoom`
|
|
52
|
-
answers it as it would anywhere.
|
|
57
|
+
answers it as it would anywhere. From the second finger on, both are the pinch's,
|
|
58
|
+
and a `longpress` waiting on the first gives up. `pan` alone leaves the wheel to
|
|
59
|
+
the page.
|
|
53
60
|
|
|
54
61
|
### A surface that scrolls past: `data-pan-after-hold`
|
|
55
62
|
|
package/docs/resource.md
CHANGED
|
@@ -42,6 +42,7 @@ looks like ([data_states.md](./data_states.md#data-and-loading-are-independent))
|
|
|
42
42
|
- [`.many(propertyName, childResource, restCallbacks)`](#manypropertyname-childresource-restcallbacks)
|
|
43
43
|
- [`.scopedOne(propertyName, { idKey, GET, POST, PUT, PATCH, DELETE })`](#scopedonepropertyname--idkey-get-post-put-patch-delete-)
|
|
44
44
|
- [`.scopedMany(propertyName, { idKey, GET, GET_MANY, POST, PUT, PATCH, DELETE, … })`](#scopedmanypropertyname--idkey-get-get_many-post-put-patch-delete--)
|
|
45
|
+
- [A relation declared on a scoped child](#a-relation-declared-on-a-scoped-child)
|
|
45
46
|
- [When the backend answers a sub-route with the whole parent](#when-the-backend-answers-a-sub-route-with-the-whole-parent)
|
|
46
47
|
- [Relations and autorerun](#relations-and-autorerun)
|
|
47
48
|
- [`withParams()`: a scope with reruns of its own](#withparams-a-scope-with-reruns-of-its-own)
|
|
@@ -359,6 +360,43 @@ const GAME_CANDIDATES = GAME.scopedMany("candidates", {
|
|
|
359
360
|
`idKey` names the child's own key inside its owner (`user_id` above); it defaults
|
|
360
361
|
to `"id"`.
|
|
361
362
|
|
|
363
|
+
### A relation declared on a scoped child
|
|
364
|
+
|
|
365
|
+
A scoped child takes relations of its own — a column pointing at a shared data
|
|
366
|
+
type:
|
|
367
|
+
|
|
368
|
+
```js
|
|
369
|
+
const TABLE_COLUMNS = TABLE.scopedMany("columns", {
|
|
370
|
+
idKey: "name",
|
|
371
|
+
GET_MANY: async ({ id }) => [id, await fetchJson(`/tables/${id}/columns`)],
|
|
372
|
+
// [id, [{ name: "email", dataType: { id: 2, name: "varchar" } }, …]]
|
|
373
|
+
PATCH: async ({ id, name, ...props }) => [
|
|
374
|
+
id,
|
|
375
|
+
await fetchJson(`/tables/${id}/columns/${name}`, {
|
|
376
|
+
method: "PATCH",
|
|
377
|
+
body: props,
|
|
378
|
+
}),
|
|
379
|
+
],
|
|
380
|
+
});
|
|
381
|
+
TABLE_COLUMNS.one("dataType", DATA_TYPE);
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Every column gets a reactive `dataType` read from the `DATA_TYPE` store, fed by
|
|
385
|
+
what the scoped child's callbacks embed. The relation itself takes none of the
|
|
386
|
+
callbacks whose result names the column — `.one()`'s `GET`/`PUT`/`DELETE`,
|
|
387
|
+
`.many()`'s `GET_MANY`/`DELETE`/`DELETE_MANY`, and every callback of a
|
|
388
|
+
`.scopedOne()`/`.scopedMany()`, whose `ownerId` would be the column: they name
|
|
389
|
+
it by its `name` alone, and a column exists only inside its table — two tables
|
|
390
|
+
can each have an `email`. Declaring one throws. A column's data type is read and
|
|
391
|
+
changed through `TABLE_COLUMNS`, whose results say which table
|
|
392
|
+
(`[id, { name, dataType }]`); the fields of a data type itself, through
|
|
393
|
+
`DATA_TYPE`.
|
|
394
|
+
|
|
395
|
+
A `.scopedOne()`/`.scopedMany()` chained on a scoped child works the same way,
|
|
396
|
+
and keeps one value per column: `TABLE_COLUMNS.scopedMany("constraints")` gives
|
|
397
|
+
`users.email` and `admins.email` a collection each, fed by the `constraints`
|
|
398
|
+
embedded in each table's columns.
|
|
399
|
+
|
|
362
400
|
## When the backend answers a sub-route with the whole parent
|
|
363
401
|
|
|
364
402
|
This is the common REST shape, and it is the reason `op` dispatch feels
|
|
@@ -405,7 +443,8 @@ parent's own fields change too, either let the parent GET rerun (see below) or
|
|
|
405
443
|
Relationship mutations do **not** invalidate their parent by default. The exact
|
|
406
444
|
rules, verified by `src/state/rest/tests/resource_graph_parent_rerun.test.js`:
|
|
407
445
|
|
|
408
|
-
- `.scopedMany` child **POST** reruns the owner's singular `GET
|
|
446
|
+
- `.scopedMany` child **POST** reruns the owner's singular `GET`, whether it
|
|
447
|
+
goes through the child or through a `withParams()` scope of it — but only when
|
|
409
448
|
the last GET response actually embedded that property. GET_MANY on the parent
|
|
410
449
|
is never rerun by a child POST (a list of parents is not stale because one of
|
|
411
450
|
them gained a child).
|
|
@@ -459,6 +498,11 @@ share is the **store**: an item updated through one is the same object in the
|
|
|
459
498
|
others, so the fields of a row change everywhere without a request — only the
|
|
460
499
|
membership of each list is a question its own scope answers.
|
|
461
500
|
|
|
501
|
+
It scopes a relation as well as a resource, and the scope's actions are the
|
|
502
|
+
relation's: `TABLE_COLUMNS.withParams({ withTypes: true }).GET_MANY` keeps the
|
|
503
|
+
`[ownerId, items]` contract of `.scopedMany()` and replaces that table's
|
|
504
|
+
columns.
|
|
505
|
+
|
|
462
506
|
`withParams()` chains, merging the params —
|
|
463
507
|
`USER.withParams({ role: "admin" }).withParams({ gender: "male" })` is
|
|
464
508
|
`USER.withParams({ role: "admin", gender: "male" })`. Its second argument takes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/navi",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.391",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Library of components including navigation to create frontend applications",
|
|
6
6
|
"repository": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"preact": "^11.0.0-rc.2"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@jsenv/dom": "0.17.
|
|
37
|
+
"@jsenv/dom": "0.17.74",
|
|
38
38
|
"@jsenv/humanize": "1.8.5",
|
|
39
39
|
"@jsenv/validity": "0.4.5"
|
|
40
40
|
},
|