@yuneta/gobj-ui 7.23.69 → 7.23.71

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 CHANGED
@@ -1266,6 +1266,55 @@ a level or two, with a count on every cut.
1266
1266
 
1267
1267
  One consumer key came with it: `show more`, the chip's tooltip.
1268
1268
 
1269
+ ### Layouts: what G6 offers, and the two made for a treedb
1270
+
1271
+ What a treedb graph IS, once folded: a **forest read left to right**. A main
1272
+ topic is a tree (places: country, region, site, hall), the other topics hang
1273
+ from its nodes through hooks, a record may hang from two parents (a device
1274
+ from its place AND its controller), and every visible node was reached from a
1275
+ root. Tens to a few hundred cards on screen, never the store.
1276
+
1277
+ G6 5.1 registers these layouts, and this is how each meets that shape:
1278
+
1279
+ | layout | what it does | for a treedb |
1280
+ |---|---|---|
1281
+ | `dagre` / `antv-dagre` | layered DAG: longest-path ranks, crossing minimisation, one direction | the right reading (LR); but the crossing heuristic **reorders the siblings on every run** — open one hook and the column next to it shuffles — and it is the one thing that takes time on a big expansion |
1282
+ | `compact-box`, `indented`, `dendrogram`, `mindmap` | @antv/hierarchy tree layouts | the shape wanted, but G6 runs them on a tree it **builds from the edges** (`createTreeStructure`): a node with two parents lands under whichever parent the builder met first, unstably |
1283
+ | `radial` | MDS on graph distances from a focus node, a ring per depth, overlaps pushed apart afterwards | the right idea — a hall with a hundred devices is a **fan**, not a column — but the ring radius is one it is TOLD: twenty cards of 172px on a ring of radius 200 have 52px each and pile up. Tried, and replaced by our own (below) |
1284
+ | `force`, `d3-force`, `force-atlas2`, `fruchterman` | physics | scatter a tree: the pile with springs. `d3-force` and `force-atlas2` stay in the picker for the rare flat treedb |
1285
+ | `circular`, `concentric`, `grid`, `mds`, `random` | rings, rings by degree, a grid, projection, noise | none knows a parent from a child |
1286
+ | `combo-combined`, `fishbone` | combos / cause-effect | not this data |
1287
+
1288
+ So three of our own, in `treedb_layout.js` (pure, tested), registered as G6
1289
+ layouts by three thin adapters in `c_g6_nodes_tree.js`:
1290
+
1291
+ - **`treedb-tree`** — the classic tidy tree, left to right. A column per
1292
+ depth as wide as its widest card, a node centred on the block of its
1293
+ children, siblings stacked with `nodesep`. **The default** for a treedb
1294
+ nobody has arranged (was `dagre`).
1295
+ - **`treedb-outline`** — one node per row, indented by depth: what a JSON
1296
+ viewer draws, and what a treedb is when read as one. Tall, but nothing is
1297
+ ever beside anything.
1298
+ - **`radial`** (`treedb-radial`) — the root in the middle, a ring per depth,
1299
+ every subtree an angular **sector** proportional to its leaves, and the
1300
+ radius of each ring the larger of one step out from the ring before and
1301
+ the length its cards need side by side. A fan that cannot overlap by
1302
+ construction; several roots share the circle around an empty centre.
1303
+
1304
+ Both take the **same spanning tree**, chosen deterministically: roots are the
1305
+ nodes with no incoming edge, in node order; a node belongs to the **first
1306
+ parent that reaches it** in a breadth-first walk (the place, not the
1307
+ controller, because the place's column came first) and its other links are
1308
+ drawn as edges across the tree; the children of a node are ordered by the
1309
+ **hook they hang from** (the parent's port order — the schema's column order)
1310
+ and then by node order (record order, the pages' order); a cycle nothing
1311
+ reaches gets a root. Consequences that dagre cannot give: O(n), no crossing
1312
+ heuristic, and **opening a hook moves nothing that is not under or beside
1313
+ it** — the cards keep their order, the eye keeps its place, and the `+N` chip
1314
+ sits at the end of its own hook's children. The hook rank comes from the
1315
+ edge's `sourcePort` looked up in the parent's ports, so the adapter needs no
1316
+ model, only the G6 data.
1317
+
1269
1318
  ### The legend is the graph's layer control
1270
1319
 
1271
1320
  The legend strip under the toolbar is **always there** now (the *Legend*
@@ -6403,6 +6403,57 @@ function plan_toolbar(wanted) {
6403
6403
  };
6404
6404
  }
6405
6405
  //#endregion
6406
+ //#region src/form_field_readonly.js
6407
+ /***********************************************************************
6408
+ * form_field_readonly.js
6409
+ *
6410
+ * Is this field of the form read-only?
6411
+ *
6412
+ * Pure, so the rule can be tested without a DOM: the gclass turns
6413
+ * the answer into `readonly`/`disabled` on a control, this decides
6414
+ * the answer. Same split as form_toolbar_plan.js and
6415
+ * treedb_write_plan.js.
6416
+ *
6417
+ * The rule it exists to state ONCE: **`writable` governs the WRITE
6418
+ * of a column's VALUE, and an fkey is not written — it is LINKED.**
6419
+ * An fkey column is normally declared with no `writable` flag at
6420
+ * all (`treedb_authzs`'s `users.roles` is `['fkey']`, and so is
6421
+ * almost every fkey in the tree), so reading "not writable" as "not
6422
+ * editable" takes away the only way to link a record to its parent
6423
+ * — with `users.roles`, the only way to give a person a role.
6424
+ *
6425
+ * The other half of this rule is already written down in
6426
+ * c_yui_treedb_topic_with_form.js, where the record travels back:
6427
+ * the form sends "the writable cols, the fkeys (a link is edited by
6428
+ * linking) and the pkey". The two halves have to agree, and when
6429
+ * they did not, the form disabled the control whose value the save
6430
+ * path was still waiting for.
6431
+ *
6432
+ * A `file` column is an fkey too (flagged `['fkey','file']`) and is
6433
+ * NOT covered: it answers `type: "file"`, its bytes travel beside
6434
+ * the record, and the SDK declares as legal a `file` column that
6435
+ * only a load fills.
6436
+ *
6437
+ * Copyright (c) 2026, ArtGins.
6438
+ * All Rights Reserved.
6439
+ ***********************************************************************/
6440
+ /***************************************************************
6441
+ * field_is_readonly(form_readonly, field_desc) -> boolean
6442
+ *
6443
+ * form_readonly the FORM is read-only: a record opened to be
6444
+ * looked at, or a store nobody may write. It is
6445
+ * a property of the opening, not of the schema,
6446
+ * and it wins over everything.
6447
+ * field_desc as treedb_get_field_desc() answers it
6448
+ * (`type`, `is_writable`).
6449
+ ***************************************************************/
6450
+ function field_is_readonly(form_readonly, field_desc) {
6451
+ if (form_readonly) return true;
6452
+ let desc = field_desc || {};
6453
+ if (desc.type === "fkey") return false;
6454
+ return !desc.is_writable;
6455
+ }
6456
+ //#endregion
6406
6457
  //#region src/yui_theme.js
6407
6458
  /***********************************************************************
6408
6459
  * yui_theme.js
@@ -7215,7 +7266,7 @@ function build_form_field_conf(gobj, field_desc) {
7215
7266
  placeholder: "",
7216
7267
  options: [],
7217
7268
  extras: {},
7218
- readonly: (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "readonly") || !field_desc.is_writable,
7269
+ readonly: field_is_readonly((0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "readonly"), field_desc),
7219
7270
  required: field_desc.is_required,
7220
7271
  hidden: field_desc.is_hidden,
7221
7272
  default_value: field_desc.default_value
@@ -27314,6 +27365,329 @@ function fold_reveal(model, state, node_key) {
27314
27365
  return true;
27315
27366
  }
27316
27367
  //#endregion
27368
+ //#region src/treedb_layout.js
27369
+ /***********************************************************************
27370
+ * treedb_layout.js
27371
+ *
27372
+ * Two layouts made for a treedb, and nothing else.
27373
+ *
27374
+ * What a treedb graph IS, once it is folded (treedb_fold_model.js):
27375
+ * a forest read left to right. A main topic is a tree (places:
27376
+ * country, region, site, hall), the other topics hang from its
27377
+ * nodes through hooks (devices, users, controllers), a record may
27378
+ * hang from two parents (a device from its place AND its
27379
+ * controller), and every visible node was reached from a root.
27380
+ * Tens to a few hundred cards on screen, never the whole store.
27381
+ *
27382
+ * G6's own layouts either do not know that or pay for not knowing:
27383
+ *
27384
+ * - `dagre` gets the reading direction right and then ranks by
27385
+ * longest path and minimises crossings with a heuristic that
27386
+ * REORDERS the siblings on every run -- open one hook and the
27387
+ * column next to it shuffles. It is O(n·m) per sweep and it is
27388
+ * the one thing that takes time on a big expansion.
27389
+ * - the tree layouts (`compact-box`, `indented`, `dendrogram`,
27390
+ * `mindmap`) draw exactly the shape wanted, but G6 runs them on
27391
+ * a TREE it builds from the edges: a node with two parents is
27392
+ * placed by whichever parent the builder met first, unstably.
27393
+ * - the force family scatters a tree, which is the pile with
27394
+ * physics.
27395
+ *
27396
+ * So: a tidy tree (`tree`) and an outline (`outline`), both fed by
27397
+ * the SAME spanning tree, chosen deterministically:
27398
+ *
27399
+ * - roots are the nodes with no incoming edge, in node order;
27400
+ * - a node belongs to the FIRST parent that reaches it in a
27401
+ * breadth-first walk from the roots -- the place, not the
27402
+ * controller, because the place's column came first -- and the
27403
+ * other links are drawn as edges across the tree;
27404
+ * - the children of a node are ordered by the HOOK they hang from
27405
+ * (the parent's port order, which is the schema's column order)
27406
+ * and then by node order (record order, the pages' order);
27407
+ * - a node nothing reaches (a cycle) is a root too.
27408
+ *
27409
+ * `tree`: the classic tidy tree, left to right. Each depth is a
27410
+ * column as wide as its widest card; a node is centred on the
27411
+ * block of its children; siblings stack with `nodesep` between
27412
+ * them. O(n), and opening a hook moves NOTHING that is not below
27413
+ * or beside it -- the cards keep their order, the eye keeps its
27414
+ * place.
27415
+ *
27416
+ * `outline`: one node per row, indented by depth -- what a JSON
27417
+ * viewer draws, and what a treedb is when read as one. Tall, but
27418
+ * nothing is ever beside anything: the reader scrolls a list.
27419
+ *
27420
+ * Pure: takes plain nodes and edges, returns positions. The G6
27421
+ * classes in c_g6_nodes_tree.js are two thin adapters over it.
27422
+ *
27423
+ * Copyright (c) 2026, ArtGins.
27424
+ * All Rights Reserved.
27425
+ ***********************************************************************/
27426
+ var DEFAULTS = {
27427
+ nodesep: 18,
27428
+ ranksep: 110,
27429
+ indent: 48
27430
+ };
27431
+ /************************************************************
27432
+ * The spanning tree of a graph, deterministic.
27433
+ *
27434
+ * nodes [{id, w, h, order}] order: creation index
27435
+ * edges [{source, target, rank}] rank: the hook's position in
27436
+ * the parent's ports (0 = first)
27437
+ *
27438
+ * Returns {roots: [id], children: Map<id, [id]>, depth: Map<id, n>,
27439
+ * by_id: Map<id, node>}
27440
+ ************************************************************/
27441
+ function spanning_tree(nodes, edges) {
27442
+ let by_id = /* @__PURE__ */ new Map();
27443
+ for (let i = 0; i < nodes.length; i++) {
27444
+ let n = nodes[i];
27445
+ by_id.set(n.id, Object.assign({ order: i }, n));
27446
+ }
27447
+ let out = /* @__PURE__ */ new Map();
27448
+ let has_parent = /* @__PURE__ */ new Set();
27449
+ for (let e of edges) {
27450
+ if (!by_id.has(e.source) || !by_id.has(e.target) || e.source === e.target) continue;
27451
+ if (!out.has(e.source)) out.set(e.source, []);
27452
+ out.get(e.source).push({
27453
+ id: e.target,
27454
+ rank: e.rank > 0 ? e.rank : 0
27455
+ });
27456
+ has_parent.add(e.target);
27457
+ }
27458
+ for (let list of out.values()) list.sort((a, b) => {
27459
+ if (a.rank !== b.rank) return a.rank - b.rank;
27460
+ return by_id.get(a.id).order - by_id.get(b.id).order;
27461
+ });
27462
+ let roots = [];
27463
+ for (let n of by_id.values()) if (!has_parent.has(n.id)) roots.push(n.id);
27464
+ let children = /* @__PURE__ */ new Map();
27465
+ let depth = /* @__PURE__ */ new Map();
27466
+ let assign = (start) => {
27467
+ let queue = [start];
27468
+ depth.set(start, 0);
27469
+ while (queue.length) {
27470
+ let id = queue.shift();
27471
+ let kids = [];
27472
+ for (let link of out.get(id) || []) {
27473
+ if (depth.has(link.id)) continue;
27474
+ depth.set(link.id, depth.get(id) + 1);
27475
+ kids.push(link.id);
27476
+ queue.push(link.id);
27477
+ }
27478
+ children.set(id, kids);
27479
+ }
27480
+ };
27481
+ for (let root of roots) assign(root);
27482
+ for (let n of by_id.values()) if (!depth.has(n.id)) {
27483
+ roots.push(n.id);
27484
+ assign(n.id);
27485
+ }
27486
+ return {
27487
+ roots,
27488
+ children,
27489
+ depth,
27490
+ by_id
27491
+ };
27492
+ }
27493
+ /************************************************************
27494
+ * The tidy tree, left to right.
27495
+ *
27496
+ * Returns Map<id, {x, y}> with the CENTRE of each node, the way G6
27497
+ * positions a node.
27498
+ ************************************************************/
27499
+ function layout_tree(nodes, edges, opts) {
27500
+ let o = Object.assign({}, DEFAULTS, opts || {});
27501
+ let t = spanning_tree(nodes, edges);
27502
+ let pos = /* @__PURE__ */ new Map();
27503
+ let col_w = [];
27504
+ for (let [id, d] of t.depth) {
27505
+ let w = t.by_id.get(id).w;
27506
+ col_w[d] = Math.max(col_w[d] || 0, w);
27507
+ }
27508
+ let col_x = [];
27509
+ let x = 0;
27510
+ for (let d = 0; d < col_w.length; d++) {
27511
+ col_x[d] = x;
27512
+ x += (col_w[d] || 0) + o.ranksep;
27513
+ }
27514
+ let height = /* @__PURE__ */ new Map();
27515
+ let measure = (id) => {
27516
+ let kids = t.children.get(id) || [];
27517
+ let own = t.by_id.get(id).h;
27518
+ if (!kids.length) {
27519
+ height.set(id, own);
27520
+ return own;
27521
+ }
27522
+ let sum = 0;
27523
+ for (let i = 0; i < kids.length; i++) {
27524
+ sum += measure(kids[i]);
27525
+ if (i > 0) sum += o.nodesep;
27526
+ }
27527
+ let h = Math.max(own, sum);
27528
+ height.set(id, h);
27529
+ return h;
27530
+ };
27531
+ for (let root of t.roots) measure(root);
27532
+ let place = (id, top) => {
27533
+ let n = t.by_id.get(id);
27534
+ let d = t.depth.get(id);
27535
+ let kids = t.children.get(id) || [];
27536
+ let block = height.get(id);
27537
+ let cx = col_x[d] + (col_w[d] - n.w) / 2 + n.w / 2;
27538
+ if (!kids.length) {
27539
+ pos.set(id, {
27540
+ x: cx,
27541
+ y: top + block / 2
27542
+ });
27543
+ return;
27544
+ }
27545
+ let kids_h = 0;
27546
+ for (let i = 0; i < kids.length; i++) {
27547
+ kids_h += height.get(kids[i]);
27548
+ if (i > 0) kids_h += o.nodesep;
27549
+ }
27550
+ let cursor = top + (block - kids_h) / 2;
27551
+ for (let kid of kids) {
27552
+ place(kid, cursor);
27553
+ cursor += height.get(kid) + o.nodesep;
27554
+ }
27555
+ pos.set(id, {
27556
+ x: cx,
27557
+ y: top + block / 2
27558
+ });
27559
+ };
27560
+ let top = 0;
27561
+ for (let root of t.roots) {
27562
+ place(root, top);
27563
+ top += height.get(root) + o.nodesep * 2;
27564
+ }
27565
+ return pos;
27566
+ }
27567
+ /************************************************************
27568
+ * The radial tree: the root in the middle, a ring per depth.
27569
+ *
27570
+ * G6's `radial` places by MDS on the graph distances and pushes
27571
+ * overlaps apart afterwards, with a ring radius it is TOLD; twenty
27572
+ * cards of 172px on a ring of radius 200 have 52px each and pile
27573
+ * up. This one is the radial form of the tidy tree above: every
27574
+ * subtree gets an angular SECTOR proportional to its leaves, a node
27575
+ * sits in the middle of its sector, and the radius of each ring is
27576
+ * the larger of "one step further out than the ring before" and
27577
+ * "long enough for its nodes to sit side by side" -- so a hall
27578
+ * with a hundred devices is a wide, sparse fan, and nothing
27579
+ * overlaps by construction. Several roots share the circle around
27580
+ * a virtual centre.
27581
+ *
27582
+ * ranksep the step between rings
27583
+ * nodesep the gap between neighbours on a ring
27584
+ ************************************************************/
27585
+ function layout_radial(nodes, edges, opts) {
27586
+ let o = Object.assign({}, DEFAULTS, opts || {});
27587
+ let t = spanning_tree(nodes, edges);
27588
+ let pos = /* @__PURE__ */ new Map();
27589
+ if (!t.roots.length) return pos;
27590
+ let leaves = /* @__PURE__ */ new Map();
27591
+ let count = (id) => {
27592
+ let kids = t.children.get(id) || [];
27593
+ if (!kids.length) {
27594
+ leaves.set(id, 1);
27595
+ return 1;
27596
+ }
27597
+ let n = 0;
27598
+ for (let kid of kids) n += count(kid);
27599
+ leaves.set(id, n);
27600
+ return n;
27601
+ };
27602
+ let total = 0;
27603
+ for (let root of t.roots) total += count(root);
27604
+ let single = t.roots.length === 1;
27605
+ let ring_of = (id) => t.depth.get(id) + (single ? 0 : 1);
27606
+ let angle = /* @__PURE__ */ new Map();
27607
+ let rings = [];
27608
+ let sector = (id, from, span) => {
27609
+ let a = from + span / 2;
27610
+ angle.set(id, a);
27611
+ let ring = ring_of(id);
27612
+ if (!rings[ring]) rings[ring] = [];
27613
+ let n = t.by_id.get(id);
27614
+ rings[ring].push({
27615
+ id,
27616
+ angle: a,
27617
+ diag: Math.hypot(n.w, n.h)
27618
+ });
27619
+ let cursor = from;
27620
+ for (let kid of t.children.get(id) || []) {
27621
+ let part = span * leaves.get(kid) / leaves.get(id);
27622
+ sector(kid, cursor, part);
27623
+ cursor += part;
27624
+ }
27625
+ };
27626
+ if (single) {
27627
+ let root = t.roots[0];
27628
+ angle.set(root, 0);
27629
+ let cursor = -Math.PI / 2;
27630
+ for (let kid of t.children.get(root) || []) {
27631
+ let part = 2 * Math.PI * leaves.get(kid) / leaves.get(root);
27632
+ sector(kid, cursor, part);
27633
+ cursor += part;
27634
+ }
27635
+ } else {
27636
+ let cursor = -Math.PI / 2;
27637
+ for (let root of t.roots) {
27638
+ let part = 2 * Math.PI * leaves.get(root) / total;
27639
+ sector(root, cursor, part);
27640
+ cursor += part;
27641
+ }
27642
+ }
27643
+ let radius = [0];
27644
+ for (let ring = 1; ring < rings.length; ring++) {
27645
+ let r = radius[ring - 1] + o.ranksep;
27646
+ let list = (rings[ring] || []).slice().sort((a, b) => a.angle - b.angle);
27647
+ for (let i = 0; i < list.length && list.length > 1; i++) {
27648
+ let a = list[i];
27649
+ let b = list[(i + 1) % list.length];
27650
+ let gap = i + 1 < list.length ? b.angle - a.angle : b.angle + 2 * Math.PI - a.angle;
27651
+ if (gap > 1e-9) r = Math.max(r, (a.diag / 2 + b.diag / 2 + o.nodesep) / gap);
27652
+ }
27653
+ radius[ring] = r;
27654
+ }
27655
+ for (let [id, a] of angle) {
27656
+ let r = radius[ring_of(id)] || 0;
27657
+ pos.set(id, {
27658
+ x: r * Math.cos(a),
27659
+ y: r * Math.sin(a)
27660
+ });
27661
+ }
27662
+ return pos;
27663
+ }
27664
+ /************************************************************
27665
+ * The outline: one node per row, indented by depth, in the
27666
+ * pre-order of the spanning tree. Rows are left-aligned on
27667
+ * their indent, so a column of chips reads as a list.
27668
+ ************************************************************/
27669
+ function layout_outline(nodes, edges, opts) {
27670
+ let o = Object.assign({}, DEFAULTS, opts || {});
27671
+ let t = spanning_tree(nodes, edges);
27672
+ let pos = /* @__PURE__ */ new Map();
27673
+ let y = 0;
27674
+ let visit = (id) => {
27675
+ let n = t.by_id.get(id);
27676
+ let d = t.depth.get(id);
27677
+ pos.set(id, {
27678
+ x: d * o.indent + n.w / 2,
27679
+ y: y + n.h / 2
27680
+ });
27681
+ y += n.h + o.nodesep;
27682
+ for (let kid of t.children.get(id) || []) visit(kid);
27683
+ };
27684
+ for (let root of t.roots) {
27685
+ visit(root);
27686
+ y += o.nodesep;
27687
+ }
27688
+ return pos;
27689
+ }
27690
+ //#endregion
27317
27691
  //#region node_modules/@babel/runtime/helpers/esm/typeof.js
27318
27692
  function _typeof(o) {
27319
27693
  "@babel/helpers - typeof";
@@ -54134,6 +54508,16 @@ var SELECT_RING = "rgba(59,130,246,0.95)";
54134
54508
  ***************************************************************/
54135
54509
  var _layouts = {
54136
54510
  "manual": { type: "manual" },
54511
+ "treedb-tree": {
54512
+ type: "treedb-tree",
54513
+ nodesep: 18,
54514
+ ranksep: 110
54515
+ },
54516
+ "treedb-outline": {
54517
+ type: "treedb-outline",
54518
+ nodesep: 12,
54519
+ indent: 48
54520
+ },
54137
54521
  "dagre": {
54138
54522
  type: "dagre",
54139
54523
  rankdir: "LR",
@@ -54146,6 +54530,11 @@ var _layouts = {
54146
54530
  nodesep: 30,
54147
54531
  ranksep: 80
54148
54532
  },
54533
+ "radial": {
54534
+ type: "treedb-radial",
54535
+ nodesep: 24,
54536
+ ranksep: 180
54537
+ },
54149
54538
  "d3-force": {
54150
54539
  type: "d3-force",
54151
54540
  link: {
@@ -54425,6 +54814,9 @@ function register_layouts(gobj) {
54425
54814
  if (!_g6_extensions_registered) {
54426
54815
  _g6_extensions_registered = true;
54427
54816
  (0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "manual", ManualLayout);
54817
+ (0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "treedb-tree", TreedbTreeLayout);
54818
+ (0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "treedb-outline", TreedbOutlineLayout);
54819
+ (0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "treedb-radial", TreedbRadialLayout);
54428
54820
  (0, _antv_g6.register)(_antv_g6.ExtensionCategory.NODE, "light", LightNode);
54429
54821
  }
54430
54822
  }
@@ -55036,8 +55428,13 @@ function build_ports(gobj, desc) {
55036
55428
  * included, because the saved arrangements were made with the
55037
55429
  * ports on the top and bottom edges.
55038
55430
  ************************************************************/
55431
+ var LR_LAYOUTS = [
55432
+ "dagre",
55433
+ "treedb-tree",
55434
+ "treedb-outline"
55435
+ ];
55039
55436
  function layout_direction(gobj) {
55040
- return gobj.priv.layout === "dagre" ? "LR" : "TB";
55437
+ return (0, _yuneta_gobj_js.str_in_list)(LR_LAYOUTS, gobj.priv.layout) ? "LR" : "TB";
55041
55438
  }
55042
55439
  function edge_type_for(gobj) {
55043
55440
  return layout_direction(gobj) === "LR" ? "cubic-horizontal" : "cubic";
@@ -56037,6 +56434,73 @@ var ManualLayout = class extends _antv_g6.BaseLayout {
56037
56434
  }
56038
56435
  };
56039
56436
  /************************************************************
56437
+ * Custom G6 layouts: TreedbTreeLayout / TreedbOutlineLayout.
56438
+ *
56439
+ * Thin adapters over treedb_layout.js: the nodes with their sizes,
56440
+ * the edges with the RANK of the hook they leave by (the position
56441
+ * of the source port in the parent's ports, which is the schema's
56442
+ * column order), and the positions back. A `+N` chip's edge has a
56443
+ * source port too, so the chip sits at the end of its hook's
56444
+ * children, where the page ends.
56445
+ ************************************************************/
56446
+ function treedb_layout_input(data) {
56447
+ const { nodes = [], edges = [] } = data;
56448
+ let ports_of = /* @__PURE__ */ new Map();
56449
+ return {
56450
+ nodes: nodes.map((node) => {
56451
+ let size = node.style && node.style.size || [172, 96];
56452
+ let w = (0, _yuneta_gobj_js.is_array)(size) ? size[0] : size;
56453
+ let h = (0, _yuneta_gobj_js.is_array)(size) ? size.length > 1 ? size[1] : size[0] : size;
56454
+ let ports = node.style && (0, _yuneta_gobj_js.is_array)(node.style.ports) ? node.style.ports : [];
56455
+ ports_of.set(node.id, ports.map((p) => p.key));
56456
+ return {
56457
+ id: node.id,
56458
+ w,
56459
+ h
56460
+ };
56461
+ }),
56462
+ edges: edges.map((edge) => {
56463
+ let port = edge.style ? edge.style.sourcePort : void 0;
56464
+ let keys = ports_of.get(edge.source) || [];
56465
+ let rank = port ? keys.indexOf(port) : -1;
56466
+ return {
56467
+ source: edge.source,
56468
+ target: edge.target,
56469
+ rank: rank >= 0 ? rank : 0
56470
+ };
56471
+ })
56472
+ };
56473
+ }
56474
+ function treedb_layout_output(pos) {
56475
+ let out = [];
56476
+ for (let [id, p] of pos) out.push({
56477
+ id,
56478
+ style: {
56479
+ x: p.x,
56480
+ y: p.y
56481
+ }
56482
+ });
56483
+ return { nodes: out };
56484
+ }
56485
+ var TreedbTreeLayout = class extends _antv_g6.BaseLayout {
56486
+ async execute(data, options) {
56487
+ let input = treedb_layout_input(data);
56488
+ return treedb_layout_output(layout_tree(input.nodes, input.edges, options));
56489
+ }
56490
+ };
56491
+ var TreedbOutlineLayout = class extends _antv_g6.BaseLayout {
56492
+ async execute(data, options) {
56493
+ let input = treedb_layout_input(data);
56494
+ return treedb_layout_output(layout_outline(input.nodes, input.edges, options));
56495
+ }
56496
+ };
56497
+ var TreedbRadialLayout = class extends _antv_g6.BaseLayout {
56498
+ async execute(data, options) {
56499
+ let input = treedb_layout_input(data);
56500
+ return treedb_layout_output(layout_radial(input.nodes, input.edges, options));
56501
+ }
56502
+ };
56503
+ /************************************************************
56040
56504
  * Node selection and resize handles
56041
56505
  ************************************************************/
56042
56506
  var RESIZE_HANDLE_SIZE = 8;
@@ -57698,7 +58162,7 @@ function auto_layout(gobj) {
57698
58162
  if (priv._layout_asked) return false;
57699
58163
  if (priv._nodes_total > 0 && priv._nodes_placed * 2 > priv._nodes_total) return false;
57700
58164
  if (!priv.graph) return false;
57701
- let name = "dagre";
58165
+ let name = "treedb-tree";
57702
58166
  (0, _yuneta_gobj_js.gobj_write_attr)(gobj, "layout", name);
57703
58167
  try {
57704
58168
  priv.graph.setLayout(_layouts[name]);
@@ -60535,6 +60999,9 @@ function option_label(name) {
60535
60999
  case "writing": return (0, i18next.t)("writing");
60536
61000
  case "edition": return (0, i18next.t)("edition");
60537
61001
  case "manual": return (0, i18next.t)("manual");
61002
+ case "treedb-tree": return (0, i18next.t)("treedb-tree");
61003
+ case "treedb-outline": return (0, i18next.t)("treedb-outline");
61004
+ case "radial": return (0, i18next.t)("radial");
60538
61005
  case "dagre": return (0, i18next.t)("dagre");
60539
61006
  case "antv-dagre": return (0, i18next.t)("antv-dagre");
60540
61007
  case "d3-force": return (0, i18next.t)("d3-force");