@yuneta/gobj-ui 7.23.29 → 7.23.31
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/README.md +175 -2
- package/dist/gobj-ui.cjs.js +1008 -197
- package/dist/gobj-ui.es.js +1009 -198
- package/package.json +1 -1
- package/src/c_yui_gobj_tree_js.js +465 -249
- package/src/c_yui_json_graph.js +30 -4
- package/src/c_yui_treedb_graph.js +20 -6
- package/src/gclass_describe.js +234 -0
- package/src/gclass_describe.test.js +125 -0
- package/src/gobj_tree_model.js +436 -0
- package/src/gobj_tree_model.test.js +184 -0
- package/src/yui_gclass_view.js +290 -0
package/README.md
CHANGED
|
@@ -431,7 +431,21 @@ sentinels present it degrades to a plain client-side collapsible tree.
|
|
|
431
431
|
questions:
|
|
432
432
|
|
|
433
433
|
The switch reads `text · tree · graph`, flattest reading first — which is not
|
|
434
|
-
the order of arrival
|
|
434
|
+
the order of arrival.
|
|
435
|
+
|
|
436
|
+
**Which view it opens on** is decided in three steps: what the HOST asked for
|
|
437
|
+
(the `view_mode` attr), then what the READER chose last time, then the tree.
|
|
438
|
+
That is why the attr's default is the **empty string** and not `"tree"`: as a
|
|
439
|
+
default and as a host's explicit choice `"tree"` was the same string, so
|
|
440
|
+
nothing could tell *"show me the tree"* from *"I have no opinion"*, and a
|
|
441
|
+
memory that cannot see the difference has to lose to both. Pass `view_mode`
|
|
442
|
+
only to PIN a view.
|
|
443
|
+
|
|
444
|
+
The reader's choice is kept in `localStorage` under one key for the whole
|
|
445
|
+
library — which of the three views somebody reads JSON in is a habit of the
|
|
446
|
+
person, not a property of the document — and only a view they picked is
|
|
447
|
+
remembered: a mode the host pinned, or the tree we fell back to, would
|
|
448
|
+
otherwise be written back as if somebody had chosen it.
|
|
435
449
|
|
|
436
450
|
| view | question | notes |
|
|
437
451
|
|---|---|---|
|
|
@@ -439,6 +453,30 @@ the order of arrival: the viewer opens on the **tree** (`view_mode` default).
|
|
|
439
453
|
| `tree` | *where is this value, and what is around it* | the lazy view; the only one that can drill; the default |
|
|
440
454
|
| `graph` | *what shape is this* | a hosted `C_YUI_JSON_GRAPH` child (AntV/G6) |
|
|
441
455
|
|
|
456
|
+
**What the graph draws is the document, not a rearrangement of it.** Every key
|
|
457
|
+
is a ROW of its card, containers included — `cols` is one key of a topic dict
|
|
458
|
+
exactly like `pkey` is, and a drawing that leaves it out does not say what the
|
|
459
|
+
document says. What a container row does NOT get is its contents repeated
|
|
460
|
+
underneath it: the row says `[14]` and the fourteen cards say the rest, which
|
|
461
|
+
is the part that has to scale.
|
|
462
|
+
|
|
463
|
+
A container with **no scalars of its own** gets no card at all: it is not a
|
|
464
|
+
thing, it is a LIST of things, described by the row that names it plus the
|
|
465
|
+
edges to what it holds, and its children hang from its parent. The root always
|
|
466
|
+
keeps a card.
|
|
467
|
+
|
|
468
|
+
Each container key opens a **G6 port** on the line of its own row, and its edge
|
|
469
|
+
leaves from there; the edge carries an arrowhead and arrives at an `in` port
|
|
470
|
+
centred above the target card's title. Ports on an html node need care: the
|
|
471
|
+
HTML is a DOM layer over the canvas, so a port fully inside the box is painted
|
|
472
|
+
under the card — they sit ON the border.
|
|
473
|
+
|
|
474
|
+
Cards are `JSON_CARD` and carry `data-json-path` (`GOBJ_CARD` /
|
|
475
|
+
`data-gobj-name` in the gobj tree, `TREEDB_CARD` in the treedb graph): a gclass
|
|
476
|
+
that builds DOM owes the Inspector a readable tree, and the anchor's mark needs
|
|
477
|
+
something to find its card by after a rebuild — the node id does not survive
|
|
478
|
+
one, the path does.
|
|
479
|
+
|
|
442
480
|
Since `7.23.2` the schema and cell-JSON popups of `C_YUI_TREEDB_TOPIC_WITH_FORM`
|
|
443
481
|
present that viewer as a floating `C_YUI_WINDOW` on a laptop — movable,
|
|
444
482
|
resizable, maximisable, position remembered — and keep the modal sheet on a
|
|
@@ -790,6 +828,7 @@ Two implementation notes worth keeping:
|
|
|
790
828
|
| ── | |
|
|
791
829
|
| fit | `fitView()`: the whole graph in the viewport |
|
|
792
830
|
| **`1:1`** | `zoomTo(1)`: actual size |
|
|
831
|
+
| **anchor** (crosshairs) | pick one element; every zoom then leaves it in the middle |
|
|
793
832
|
| ── | |
|
|
794
833
|
| **fit to selection** | `fit`, for the part that is selected (edition only, disabled while nothing is) |
|
|
795
834
|
| ── | |
|
|
@@ -830,6 +869,71 @@ so it survived that — two light islands over a dark canvas.
|
|
|
830
869
|
(all tooltips, so a host that has not defined them shows the key on hover and
|
|
831
870
|
nothing else breaks).
|
|
832
871
|
|
|
872
|
+
### The anchor: one element the camera holds
|
|
873
|
+
|
|
874
|
+
The same crosshairs button is in all three graphs' toolbars, drawn once in
|
|
875
|
+
`yui_graph_camera.js`. Why it exists: a graph that FITS on screen is unreadable
|
|
876
|
+
at the zoom that makes it fit — one topic's schema fits at 37%, where every
|
|
877
|
+
card is grey texture — and the zoom that makes it readable does not fit. So the
|
|
878
|
+
useful view is always a fraction of the document, and WHICH fraction was
|
|
879
|
+
nobody's decision: `1:1` translated to the layout's origin, a corner with
|
|
880
|
+
nothing in it, and the reader then hunted for the node they had been looking at.
|
|
881
|
+
|
|
882
|
+
Three states, because two could not say what a press does: `off`, **arming**
|
|
883
|
+
(the attention colour, and the pointer over the canvas turns to a crosshair)
|
|
884
|
+
and **on** (pressed). The anchored card carries a **dashed amber outline** —
|
|
885
|
+
dashed because in the treedb graph a solid amber ring already means a find
|
|
886
|
+
match and blue means the selection, so a third solid ring would be a third
|
|
887
|
+
thing to learn in one channel.
|
|
888
|
+
|
|
889
|
+
Two things a host does not have to think about but a maintainer does:
|
|
890
|
+
|
|
891
|
+
- While it is arming, `drag-element` is swapped OUT with `setBehaviors()`. With
|
|
892
|
+
it in, a click that drifts two pixels — which is every click a hand makes —
|
|
893
|
+
becomes a drag, G6 fires no `node:click`, and the pick silently does not
|
|
894
|
+
happen.
|
|
895
|
+
- The camera move is POSTED to the gclass, not made in the handler: a translate
|
|
896
|
+
issued inside G6's click dispatch or its `aftertransform` is swallowed. And
|
|
897
|
+
the translate itself is a closed form, `T = (canvasCentre - nodeWorld) *
|
|
898
|
+
zoom`, read off G6's own `getTranslateOptions()` — `focusElement()` and
|
|
899
|
+
`translateBy()` compute the right offset, resolve, and do not move the camera
|
|
900
|
+
at all.
|
|
901
|
+
|
|
902
|
+
**New keys for consumers: `anchor view`, `click the element to centre on`,
|
|
903
|
+
`centred: click to release`.**
|
|
904
|
+
|
|
905
|
+
### Moving the cards, and folding without losing your place
|
|
906
|
+
|
|
907
|
+
The JSON graph and the gobj tree take `drag-element`: a card can be dragged.
|
|
908
|
+
The position is deliberately NOT kept — both are rebuilt from their source on
|
|
909
|
+
every refresh, fold and layout change, and neither is a document of its own to
|
|
910
|
+
save it to — and it is worth having anyway, because pulling two cards apart to
|
|
911
|
+
read the lines between them is most of what a reader wants from a graph.
|
|
912
|
+
|
|
913
|
+
**Folding no longer moves anything.** It used to re-pack the tree: five
|
|
914
|
+
surviving cards would all slide 240px sideways for a fold that removed nothing
|
|
915
|
+
they could see, and the card under the finger slid out from under it. Two
|
|
916
|
+
halves:
|
|
917
|
+
|
|
918
|
+
- the card you clicked is read before the rebuild and put back afterwards
|
|
919
|
+
(`yui_graph_place_at()`, the anchor's arithmetic with the target point left
|
|
920
|
+
free);
|
|
921
|
+
- and the others stay because a fold leaves a **phantom child** — an invisible
|
|
922
|
+
node of exactly the width its children had, in the place they had in the
|
|
923
|
+
order. Reserving the width as a NUMBER does not work: the layout centres a
|
|
924
|
+
parent over its children, so a lump appended at the end moves every sibling
|
|
925
|
+
by half of it.
|
|
926
|
+
|
|
927
|
+
`collapse all` reserves nothing on purpose: it is asking for a COMPACT drawing.
|
|
928
|
+
|
|
929
|
+
**The gobj tree remembers how you left it** — layout, zoom, camera, folds and
|
|
930
|
+
anchor — in `localStorage`, keyed by the gobj's name. Not in a persistent attr
|
|
931
|
+
because only a SERVICE can save those and this gclass is hosted as a child, and
|
|
932
|
+
because how somebody left THEIR tree is a fact about that browser. The layout
|
|
933
|
+
and the folds are restored BEFORE the first build, since they decide what is
|
|
934
|
+
built; the camera after, and once only, or every fold would drag the reader
|
|
935
|
+
back.
|
|
936
|
+
|
|
833
937
|
### The graphs on a touch screen
|
|
834
938
|
|
|
835
939
|
The three G6 graphs (`C_G6_NODES_TREE` under the treedb view,
|
|
@@ -1271,6 +1375,75 @@ host can use it to toggle. The tree is a **pure child of the window**, so every
|
|
|
1271
1375
|
teardown path (the ✕, or the host destroying the window to toggle the entry
|
|
1272
1376
|
off) takes it down too.
|
|
1273
1377
|
|
|
1378
|
+
**What a card says.** Every node carries what it IS and what it is DOING,
|
|
1379
|
+
because opening a popover per node to learn it is not reading a tree:
|
|
1380
|
+
|
|
1381
|
+
| On the card | Says |
|
|
1382
|
+
|---|---|
|
|
1383
|
+
| Colour (border + left bar) | the ROLE: sky = the yuno, emerald = a service, amber = a pure child, pink = a volatil one, violet = a plain child |
|
|
1384
|
+
| Status pill | `stopped` / `running` / `playing`, coloured. `running` and `playing` are not the same thing: a gobj that runs and does not play is PAUSED, which is what the popover calls it in full |
|
|
1385
|
+
| Badges | `service`, `pure child`, `volatil child`, `disabled`, `bottom` (it has a bottom gobj), `commands` (its gclass exposes commands) |
|
|
1386
|
+
| Its own line | the FSM state |
|
|
1387
|
+
| Dashed border, dimmed | disabled — that branch is out of the game |
|
|
1388
|
+
|
|
1389
|
+
The popover adds the rest (`full name`, `parent`, `bottom gobj`, `traces`,
|
|
1390
|
+
`flags`, how many children a fold is hiding) and shows only the rows that have
|
|
1391
|
+
an answer.
|
|
1392
|
+
|
|
1393
|
+
**It draws DESCRIPTORS, not gobjs** (`gobj_tree_model.js`), which is what lets
|
|
1394
|
+
this same view show a **backend** yuno. A descriptor is plain data whose field
|
|
1395
|
+
names are the ones the C kernel's `gobj2json()` writes, and there are two
|
|
1396
|
+
producers of it:
|
|
1397
|
+
|
|
1398
|
+
```js
|
|
1399
|
+
import {describe_js_gobj, describe_backend_tree} from "@yuneta/gobj-ui/src/gobj_tree_model.js";
|
|
1400
|
+
|
|
1401
|
+
let root = describe_js_gobj(gobj_yuno(), true); /* this browser yuno */
|
|
1402
|
+
let root = describe_backend_tree(answer); /* `view-gobj-tree` */
|
|
1403
|
+
```
|
|
1404
|
+
|
|
1405
|
+
`load_tree()` calls the first one, on one line. Swapping it for the second is
|
|
1406
|
+
the whole of showing a remote yuno; nothing below that line changes. (The
|
|
1407
|
+
remote fetch itself is not wired yet.)
|
|
1408
|
+
|
|
1409
|
+
### The gclass viewer — `yui_gclass_view.js`
|
|
1410
|
+
|
|
1411
|
+
```js
|
|
1412
|
+
import {gclass_view_available, open_gclass_view, close_gclass_view}
|
|
1413
|
+
from "@yuneta/gobj-ui/src/yui_gclass_view.js";
|
|
1414
|
+
|
|
1415
|
+
let handle = open_gclass_view(host, "C_TIMER", {title_prefix: yuno_name, on_close});
|
|
1416
|
+
close_gclass_view(handle);
|
|
1417
|
+
```
|
|
1418
|
+
|
|
1419
|
+
What a GClass IS — its attrs, its commands, the methods it implements, its FSM
|
|
1420
|
+
— in a `C_YUI_JSON` window, so the FSM is a graph and the attrs table is a
|
|
1421
|
+
tree. The framework had no such viewer: the C kernel answers `view-gclass`
|
|
1422
|
+
with exactly this document and the only thing that ever read it was a terminal.
|
|
1423
|
+
|
|
1424
|
+
`gclass_describe.js` builds it for a gclass of the **browser** yuno from the
|
|
1425
|
+
gobj-js registry, in the shape `gclass2json()` answers (`id`, `gcflag`,
|
|
1426
|
+
`attrs`, `commands`, `gclass_methods`, `internal_methods`, `FSM`, plus
|
|
1427
|
+
`instances` and `trace_levels`, which the browser can answer for free). For a
|
|
1428
|
+
gclass of a **backend** yuno the host passes the answer of `view-gclass` as
|
|
1429
|
+
`opts.description` and the same window draws it.
|
|
1430
|
+
|
|
1431
|
+
`gclass_view_available()` reports whether the app registers `C_YUI_JSON` — the
|
|
1432
|
+
gobj tree asks it before drawing its `gclass` button, so an app that does not
|
|
1433
|
+
carry the viewer shows no control rather than one that fails. **Importing
|
|
1434
|
+
`c_yui_json.js` is not registering it**: an app that only pulls it in
|
|
1435
|
+
transitively (through the treedb graph, say) still has to call
|
|
1436
|
+
`register_c_yui_json()` for the button to appear.
|
|
1437
|
+
|
|
1438
|
+
> **Mount before you start a hosted view.** `mt_create` builds the DOM;
|
|
1439
|
+
> `mt_start` renders it, and a view that measures a canvas or observes its box
|
|
1440
|
+
> needs to be IN the document by then. A host that creates a viewer, reads its
|
|
1441
|
+
> `$container` and hands it to a window as `body` must therefore start the
|
|
1442
|
+
> viewer **after** the window — the window is what puts it in the document.
|
|
1443
|
+
> Started before, a graph viewer measures nothing, attaches no
|
|
1444
|
+
> `ResizeObserver`, and its canvas keeps its birth size for the life of the
|
|
1445
|
+
> window while everything resizes around it (fixed in 7.23.31).
|
|
1446
|
+
|
|
1274
1447
|
### Toolbar badge — a count pinned to an item's icon
|
|
1275
1448
|
|
|
1276
1449
|
```js
|
|
@@ -1456,7 +1629,7 @@ shapes, and the fix for each:
|
|
|
1456
1629
|
| Text built with `t()` | never changes language | `i18n` / `data-i18n` on the element (`["span", {i18n: "rows"}, t("rows")]`) |
|
|
1457
1630
|
| A composed string (`` `${key} · ${t(mode)}` ``) | carries no key at all | split it: the translatable halves get their own key. (Note `createElement2` **trims** text nodes — space a `·` separator with CSS, not with spaces.) |
|
|
1458
1631
|
| `title` / `aria-label` set with `t()` | tooltip stuck in the old language | `data-i18n-title` / `data-i18n-aria-label` |
|
|
1459
|
-
| Anything a WIDGET renders (a Tabulator header, its paginator, a formatter) | drawn once; no attribute reaches it | subscribe to the shell and re-render (below) |
|
|
1632
|
+
| Anything a WIDGET renders (a Tabulator header, its paginator, a formatter; the innerHTML of a G6 node) | drawn once; no attribute reaches it | subscribe to the shell and re-render (below). For a graph whose cards are innerHTML — the gobj tree — re-rendering means REBUILDING the graph: nothing walks inside a G6 canvas |
|
|
1460
1633
|
| DOM built AFTER start up (a node's strips, a dropdown panel) | renders the raw key — indistinguishable from a MISSING key | `yui_shell_translate(shell, $el)` right after building it (below) |
|
|
1461
1634
|
|
|
1462
1635
|
**Carrying the key is not enough for the FIRST render.** A node is born holding
|