@yuneta/gobj-ui 7.23.25 → 7.23.26

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.
@@ -9710,8 +9710,18 @@ function yui_graph_update_anchor($container, state) {
9710
9710
  * an error worth a log line per notch, they are all "there is
9711
9711
  * nothing to centre right now".
9712
9712
  ************************************************************/
9713
+ var __centring__ = /* @__PURE__ */ new WeakMap();
9713
9714
  async function yui_graph_center_on(graph, node_id) {
9714
9715
  if (!graph || !node_id) return false;
9716
+ let st = __centring__.get(graph);
9717
+ if (st && st.running) {
9718
+ st.again = node_id;
9719
+ return true;
9720
+ }
9721
+ __centring__.set(graph, {
9722
+ running: true,
9723
+ again: null
9724
+ });
9715
9725
  try {
9716
9726
  if (typeof graph.getElementData === "function" && !graph.getElementData(node_id)) return false;
9717
9727
  if (typeof graph.getElementPosition !== "function" || typeof graph.getViewportByCanvas !== "function" || typeof graph.getCanvasCenter !== "function" || typeof graph.translateTo !== "function") return false;
@@ -9727,6 +9737,13 @@ async function yui_graph_center_on(graph, node_id) {
9727
9737
  return true;
9728
9738
  } catch (e) {
9729
9739
  return false;
9740
+ } finally {
9741
+ let pending = __centring__.get(graph);
9742
+ __centring__.set(graph, {
9743
+ running: false,
9744
+ again: null
9745
+ });
9746
+ if (pending && pending.again) yui_graph_center_on(graph, pending.again);
9730
9747
  }
9731
9748
  }
9732
9749
  /************************************************************
@@ -10941,11 +10958,7 @@ function build_graph$3(gobj) {
10941
10958
  }
10942
10959
  },
10943
10960
  layout: layout_cfg.g6_layout,
10944
- behaviors: [
10945
- "drag-canvas",
10946
- "zoom-canvas",
10947
- "drag-element"
10948
- ]
10961
+ behaviors: BEHAVIORS_READING$1.slice()
10949
10962
  });
10950
10963
  if (priv.theme) graph.setTheme(priv.theme);
10951
10964
  graph.on(_antv_g6.NodeEvent.CLICK, (evt) => {
@@ -11052,6 +11065,12 @@ function build_cell_html(key, value, type, dark, matched, fold) {
11052
11065
  * forever. `+3` and `−` need no language.
11053
11066
  ************************************************************/
11054
11067
  var FOLD_SPACER = `<span style="width:24px; flex:0 0 auto;"></span>`;
11068
+ var BEHAVIORS_READING$1 = [
11069
+ "drag-canvas",
11070
+ "zoom-canvas",
11071
+ "drag-element"
11072
+ ];
11073
+ var BEHAVIORS_PICKING$1 = ["drag-canvas", "zoom-canvas"];
11055
11074
  var CARD_HEADER_H$1 = 24;
11056
11075
  var CARD_ROW_H$1 = 22;
11057
11076
  function fold_toggle_html(path, foldable, folded, branches, colors) {
@@ -11188,7 +11207,7 @@ function build_json_nodes(gobj, path, kw, nodes, edges, parent_id, parent_port)
11188
11207
  let min_width = Math.max(180, label.length * 9);
11189
11208
  let card_height = CARD_HEADER_H$1 + lines.length * CARD_ROW_H$1;
11190
11209
  let node_html = `
11191
- <div style="
11210
+ <div class="JSON_CARD" data-json-path="${(0, _yuneta_gobj_js.escapeHtml)(path)}" style="
11192
11211
  min-width: ${min_width}px;
11193
11212
  background: ${colors.bg};
11194
11213
  border: ${border_width}px ${is_dict ? "dashed" : "solid"} ${border_color};
@@ -11292,6 +11311,7 @@ function load_json(gobj) {
11292
11311
  });
11293
11312
  graph.render().then(() => {
11294
11313
  reanchor$1(gobj);
11314
+ paint_anchor_mark(gobj);
11295
11315
  if (preserve_view) {
11296
11316
  yui_graph_update_zoom((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.graph);
11297
11317
  return;
@@ -11613,10 +11633,48 @@ function reanchor$1(gobj) {
11613
11633
  yui_graph_update_anchor((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.anchor_state);
11614
11634
  }
11615
11635
  /************************************************************
11636
+ * Reading, or picking the node to anchor.
11637
+ *
11638
+ * Two visible consequences and one invisible: the cursor says
11639
+ * a click is expected, the mount says which mode it is in for
11640
+ * anyone reading the DOM, and node dragging stands aside so a
11641
+ * click that drifts is still a click.
11642
+ ************************************************************/
11643
+ function set_picking_mode$1(gobj, picking) {
11644
+ let graph = gobj.priv.graph;
11645
+ if (graph && typeof graph.setBehaviors === "function") graph.setBehaviors((picking ? BEHAVIORS_PICKING$1 : BEHAVIORS_READING$1).slice());
11646
+ let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
11647
+ if ($container) {
11648
+ let $mount = $container.querySelector(".json-graph-container");
11649
+ if ($mount) $mount.classList.toggle("JSON_GRAPH_PICKING", !!picking);
11650
+ }
11651
+ }
11652
+ /************************************************************
11653
+ * Mark the card the camera is holding.
11654
+ *
11655
+ * A class on the card's own element and not a G6 node state:
11656
+ * G6 paints no state style on an html node, so `setElementState`
11657
+ * would select it correctly and show nothing.
11658
+ *
11659
+ * Re-applied after every rebuild, because the cards are new DOM
11660
+ * each time and the mark would otherwise survive only until the
11661
+ * next fold.
11662
+ ************************************************************/
11663
+ function paint_anchor_mark(gobj) {
11664
+ let priv = gobj.priv;
11665
+ let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
11666
+ if (!$container) return;
11667
+ for (let $card of $container.querySelectorAll(".JSON_CARD_ANCHORED")) $card.classList.remove("JSON_CARD_ANCHORED");
11668
+ if (priv.anchor_state !== "on" || !priv.anchor_path) return;
11669
+ let $it = $container.querySelector(".JSON_CARD[data-json-path=\"" + CSS.escape(priv.anchor_path) + "\"]");
11670
+ if ($it) $it.classList.add("JSON_CARD_ANCHORED");
11671
+ }
11672
+ /************************************************************
11616
11673
  * Centre on the anchor, one cycle after it was chosen.
11617
11674
  ************************************************************/
11618
11675
  function ac_center_anchor$2(gobj, event, kw, src) {
11619
11676
  let priv = gobj.priv;
11677
+ paint_anchor_mark(gobj);
11620
11678
  if (priv.anchor_state === "on" && priv.anchor_id) yui_graph_center_on(priv.graph, priv.anchor_id);
11621
11679
  return 0;
11622
11680
  }
@@ -11637,6 +11695,8 @@ function ac_toggle_anchor$2(gobj, event, kw, src) {
11637
11695
  priv.anchor_path = "";
11638
11696
  }
11639
11697
  yui_graph_update_anchor((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.anchor_state);
11698
+ paint_anchor_mark(gobj);
11699
+ set_picking_mode$1(gobj, priv.anchor_state === "arming");
11640
11700
  return 0;
11641
11701
  }
11642
11702
  /************************************************************
@@ -11703,6 +11763,7 @@ function ac_node_click$4(gobj, event, kw, src) {
11703
11763
  priv.anchor_path = nodedata && nodedata.data ? nodedata.data.path : "";
11704
11764
  priv.anchor_state = "on";
11705
11765
  yui_graph_update_anchor((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.anchor_state);
11766
+ set_picking_mode$1(gobj, false);
11706
11767
  (0, _yuneta_gobj_js.gobj_post_event)(gobj, "EV_CENTER_ANCHOR", {}, gobj);
11707
11768
  return 0;
11708
11769
  }
@@ -13169,6 +13230,12 @@ var attrs_table$9 = [
13169
13230
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_INTEGER, "collapse_threshold", 0, 10, "Auto-collapse a node whose direct children exceed this number. 0 disables auto-collapse."),
13170
13231
  (0, _yuneta_gobj_js.SDATA_END)()
13171
13232
  ];
13233
+ var BEHAVIORS_READING = [
13234
+ "drag-canvas",
13235
+ "zoom-canvas",
13236
+ "drag-element"
13237
+ ];
13238
+ var BEHAVIORS_PICKING = ["drag-canvas", "zoom-canvas"];
13172
13239
  var PRIVATE_DATA$9 = {
13173
13240
  canvas_id: "",
13174
13241
  graph: null,
@@ -13650,11 +13717,7 @@ function build_graph$2(gobj) {
13650
13717
  }
13651
13718
  },
13652
13719
  layout: layout_cfg.g6_layout,
13653
- behaviors: [
13654
- "drag-canvas",
13655
- "zoom-canvas",
13656
- "drag-element"
13657
- ]
13720
+ behaviors: BEHAVIORS_READING.slice()
13658
13721
  });
13659
13722
  if (priv.theme) graph.setTheme(priv.theme);
13660
13723
  graph.on("aftertransform", () => {
@@ -14526,6 +14589,16 @@ function ac_center_anchor$1(gobj, event, kw, src) {
14526
14589
  return 0;
14527
14590
  }
14528
14591
  /************************************************************
14592
+ * Reading, or picking the node to anchor.
14593
+ ************************************************************/
14594
+ function set_picking_mode(gobj, picking) {
14595
+ let graph = gobj.priv.graph;
14596
+ if (graph && typeof graph.setBehaviors === "function") graph.setBehaviors((picking ? BEHAVIORS_PICKING : BEHAVIORS_READING).slice());
14597
+ let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
14598
+ let $mount = $container ? $container.querySelector(".gobj-tree-container") : null;
14599
+ if ($mount) $mount.classList.toggle("GOBJ_TREE_PICKING", !!picking);
14600
+ }
14601
+ /************************************************************
14529
14602
  * Arm the anchor, or let it go.
14530
14603
  *
14531
14604
  * Three states and one button, so a press ADVANCES: with no
@@ -14542,6 +14615,7 @@ function ac_toggle_anchor$1(gobj, event, kw, src) {
14542
14615
  priv.anchor_name = "";
14543
14616
  }
14544
14617
  yui_graph_update_anchor((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.anchor_state);
14618
+ set_picking_mode(gobj, priv.anchor_state === "arming");
14545
14619
  return 0;
14546
14620
  }
14547
14621
  /************************************************************
@@ -14610,6 +14684,7 @@ function ac_node_click$3(gobj, event, kw, src) {
14610
14684
  priv.anchor_name = node_data.full_name || "";
14611
14685
  priv.anchor_state = "on";
14612
14686
  yui_graph_update_anchor((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.anchor_state);
14687
+ set_picking_mode(gobj, false);
14613
14688
  (0, _yuneta_gobj_js.gobj_post_event)(gobj, "EV_CENTER_ANCHOR", {}, gobj);
14614
14689
  return 0;
14615
14690
  }
@@ -37605,7 +37680,7 @@ Text.PARSED_STYLE_LIST = new Set([].concat(_toConsumableArray(DisplayObject.PARS
37605
37680
  * * register property @see https://developer.mozilla.org/en-US/docs/Web/API/CSS/RegisterProperty
37606
37681
  * * CSS Layout API
37607
37682
  */
37608
- var CSS = {
37683
+ var CSS$1 = {
37609
37684
  /**
37610
37685
  * <number>
37611
37686
  * @see https://drafts.csswg.org/css-values-4/#number-value
@@ -47654,7 +47729,7 @@ var e = 1e-4;
47654
47729
  syntax: PropertySyntax.ANGLE
47655
47730
  }
47656
47731
  ].forEach(function(property) {
47657
- CSS.registerProperty(property);
47732
+ CSS$1.registerProperty(property);
47658
47733
  });
47659
47734
  var polarToCartesian = function polarToCartesian(centerX, centerY, radius, angleInRadian) {
47660
47735
  return {
@@ -9705,8 +9705,18 @@ function yui_graph_update_anchor($container, state) {
9705
9705
  * an error worth a log line per notch, they are all "there is
9706
9706
  * nothing to centre right now".
9707
9707
  ************************************************************/
9708
+ var __centring__ = /* @__PURE__ */ new WeakMap();
9708
9709
  async function yui_graph_center_on(graph, node_id) {
9709
9710
  if (!graph || !node_id) return false;
9711
+ let st = __centring__.get(graph);
9712
+ if (st && st.running) {
9713
+ st.again = node_id;
9714
+ return true;
9715
+ }
9716
+ __centring__.set(graph, {
9717
+ running: true,
9718
+ again: null
9719
+ });
9710
9720
  try {
9711
9721
  if (typeof graph.getElementData === "function" && !graph.getElementData(node_id)) return false;
9712
9722
  if (typeof graph.getElementPosition !== "function" || typeof graph.getViewportByCanvas !== "function" || typeof graph.getCanvasCenter !== "function" || typeof graph.translateTo !== "function") return false;
@@ -9722,6 +9732,13 @@ async function yui_graph_center_on(graph, node_id) {
9722
9732
  return true;
9723
9733
  } catch (e) {
9724
9734
  return false;
9735
+ } finally {
9736
+ let pending = __centring__.get(graph);
9737
+ __centring__.set(graph, {
9738
+ running: false,
9739
+ again: null
9740
+ });
9741
+ if (pending && pending.again) yui_graph_center_on(graph, pending.again);
9725
9742
  }
9726
9743
  }
9727
9744
  /************************************************************
@@ -10936,11 +10953,7 @@ function build_graph$3(gobj) {
10936
10953
  }
10937
10954
  },
10938
10955
  layout: layout_cfg.g6_layout,
10939
- behaviors: [
10940
- "drag-canvas",
10941
- "zoom-canvas",
10942
- "drag-element"
10943
- ]
10956
+ behaviors: BEHAVIORS_READING$1.slice()
10944
10957
  });
10945
10958
  if (priv.theme) graph.setTheme(priv.theme);
10946
10959
  graph.on(NodeEvent.CLICK, (evt) => {
@@ -11047,6 +11060,12 @@ function build_cell_html(key, value, type, dark, matched, fold) {
11047
11060
  * forever. `+3` and `−` need no language.
11048
11061
  ************************************************************/
11049
11062
  var FOLD_SPACER = `<span style="width:24px; flex:0 0 auto;"></span>`;
11063
+ var BEHAVIORS_READING$1 = [
11064
+ "drag-canvas",
11065
+ "zoom-canvas",
11066
+ "drag-element"
11067
+ ];
11068
+ var BEHAVIORS_PICKING$1 = ["drag-canvas", "zoom-canvas"];
11050
11069
  var CARD_HEADER_H$1 = 24;
11051
11070
  var CARD_ROW_H$1 = 22;
11052
11071
  function fold_toggle_html(path, foldable, folded, branches, colors) {
@@ -11183,7 +11202,7 @@ function build_json_nodes(gobj, path, kw, nodes, edges, parent_id, parent_port)
11183
11202
  let min_width = Math.max(180, label.length * 9);
11184
11203
  let card_height = CARD_HEADER_H$1 + lines.length * CARD_ROW_H$1;
11185
11204
  let node_html = `
11186
- <div style="
11205
+ <div class="JSON_CARD" data-json-path="${escapeHtml(path)}" style="
11187
11206
  min-width: ${min_width}px;
11188
11207
  background: ${colors.bg};
11189
11208
  border: ${border_width}px ${is_dict ? "dashed" : "solid"} ${border_color};
@@ -11287,6 +11306,7 @@ function load_json(gobj) {
11287
11306
  });
11288
11307
  graph.render().then(() => {
11289
11308
  reanchor$1(gobj);
11309
+ paint_anchor_mark(gobj);
11290
11310
  if (preserve_view) {
11291
11311
  yui_graph_update_zoom(gobj_read_attr(gobj, "$container"), priv.graph);
11292
11312
  return;
@@ -11608,10 +11628,48 @@ function reanchor$1(gobj) {
11608
11628
  yui_graph_update_anchor(gobj_read_attr(gobj, "$container"), priv.anchor_state);
11609
11629
  }
11610
11630
  /************************************************************
11631
+ * Reading, or picking the node to anchor.
11632
+ *
11633
+ * Two visible consequences and one invisible: the cursor says
11634
+ * a click is expected, the mount says which mode it is in for
11635
+ * anyone reading the DOM, and node dragging stands aside so a
11636
+ * click that drifts is still a click.
11637
+ ************************************************************/
11638
+ function set_picking_mode$1(gobj, picking) {
11639
+ let graph = gobj.priv.graph;
11640
+ if (graph && typeof graph.setBehaviors === "function") graph.setBehaviors((picking ? BEHAVIORS_PICKING$1 : BEHAVIORS_READING$1).slice());
11641
+ let $container = gobj_read_attr(gobj, "$container");
11642
+ if ($container) {
11643
+ let $mount = $container.querySelector(".json-graph-container");
11644
+ if ($mount) $mount.classList.toggle("JSON_GRAPH_PICKING", !!picking);
11645
+ }
11646
+ }
11647
+ /************************************************************
11648
+ * Mark the card the camera is holding.
11649
+ *
11650
+ * A class on the card's own element and not a G6 node state:
11651
+ * G6 paints no state style on an html node, so `setElementState`
11652
+ * would select it correctly and show nothing.
11653
+ *
11654
+ * Re-applied after every rebuild, because the cards are new DOM
11655
+ * each time and the mark would otherwise survive only until the
11656
+ * next fold.
11657
+ ************************************************************/
11658
+ function paint_anchor_mark(gobj) {
11659
+ let priv = gobj.priv;
11660
+ let $container = gobj_read_attr(gobj, "$container");
11661
+ if (!$container) return;
11662
+ for (let $card of $container.querySelectorAll(".JSON_CARD_ANCHORED")) $card.classList.remove("JSON_CARD_ANCHORED");
11663
+ if (priv.anchor_state !== "on" || !priv.anchor_path) return;
11664
+ let $it = $container.querySelector(".JSON_CARD[data-json-path=\"" + CSS.escape(priv.anchor_path) + "\"]");
11665
+ if ($it) $it.classList.add("JSON_CARD_ANCHORED");
11666
+ }
11667
+ /************************************************************
11611
11668
  * Centre on the anchor, one cycle after it was chosen.
11612
11669
  ************************************************************/
11613
11670
  function ac_center_anchor$2(gobj, event, kw, src) {
11614
11671
  let priv = gobj.priv;
11672
+ paint_anchor_mark(gobj);
11615
11673
  if (priv.anchor_state === "on" && priv.anchor_id) yui_graph_center_on(priv.graph, priv.anchor_id);
11616
11674
  return 0;
11617
11675
  }
@@ -11632,6 +11690,8 @@ function ac_toggle_anchor$2(gobj, event, kw, src) {
11632
11690
  priv.anchor_path = "";
11633
11691
  }
11634
11692
  yui_graph_update_anchor(gobj_read_attr(gobj, "$container"), priv.anchor_state);
11693
+ paint_anchor_mark(gobj);
11694
+ set_picking_mode$1(gobj, priv.anchor_state === "arming");
11635
11695
  return 0;
11636
11696
  }
11637
11697
  /************************************************************
@@ -11698,6 +11758,7 @@ function ac_node_click$4(gobj, event, kw, src) {
11698
11758
  priv.anchor_path = nodedata && nodedata.data ? nodedata.data.path : "";
11699
11759
  priv.anchor_state = "on";
11700
11760
  yui_graph_update_anchor(gobj_read_attr(gobj, "$container"), priv.anchor_state);
11761
+ set_picking_mode$1(gobj, false);
11701
11762
  gobj_post_event(gobj, "EV_CENTER_ANCHOR", {}, gobj);
11702
11763
  return 0;
11703
11764
  }
@@ -13164,6 +13225,12 @@ var attrs_table$9 = [
13164
13225
  SDATA(data_type_t.DTP_INTEGER, "collapse_threshold", 0, 10, "Auto-collapse a node whose direct children exceed this number. 0 disables auto-collapse."),
13165
13226
  SDATA_END()
13166
13227
  ];
13228
+ var BEHAVIORS_READING = [
13229
+ "drag-canvas",
13230
+ "zoom-canvas",
13231
+ "drag-element"
13232
+ ];
13233
+ var BEHAVIORS_PICKING = ["drag-canvas", "zoom-canvas"];
13167
13234
  var PRIVATE_DATA$9 = {
13168
13235
  canvas_id: "",
13169
13236
  graph: null,
@@ -13645,11 +13712,7 @@ function build_graph$2(gobj) {
13645
13712
  }
13646
13713
  },
13647
13714
  layout: layout_cfg.g6_layout,
13648
- behaviors: [
13649
- "drag-canvas",
13650
- "zoom-canvas",
13651
- "drag-element"
13652
- ]
13715
+ behaviors: BEHAVIORS_READING.slice()
13653
13716
  });
13654
13717
  if (priv.theme) graph.setTheme(priv.theme);
13655
13718
  graph.on("aftertransform", () => {
@@ -14521,6 +14584,16 @@ function ac_center_anchor$1(gobj, event, kw, src) {
14521
14584
  return 0;
14522
14585
  }
14523
14586
  /************************************************************
14587
+ * Reading, or picking the node to anchor.
14588
+ ************************************************************/
14589
+ function set_picking_mode(gobj, picking) {
14590
+ let graph = gobj.priv.graph;
14591
+ if (graph && typeof graph.setBehaviors === "function") graph.setBehaviors((picking ? BEHAVIORS_PICKING : BEHAVIORS_READING).slice());
14592
+ let $container = gobj_read_attr(gobj, "$container");
14593
+ let $mount = $container ? $container.querySelector(".gobj-tree-container") : null;
14594
+ if ($mount) $mount.classList.toggle("GOBJ_TREE_PICKING", !!picking);
14595
+ }
14596
+ /************************************************************
14524
14597
  * Arm the anchor, or let it go.
14525
14598
  *
14526
14599
  * Three states and one button, so a press ADVANCES: with no
@@ -14537,6 +14610,7 @@ function ac_toggle_anchor$1(gobj, event, kw, src) {
14537
14610
  priv.anchor_name = "";
14538
14611
  }
14539
14612
  yui_graph_update_anchor(gobj_read_attr(gobj, "$container"), priv.anchor_state);
14613
+ set_picking_mode(gobj, priv.anchor_state === "arming");
14540
14614
  return 0;
14541
14615
  }
14542
14616
  /************************************************************
@@ -14605,6 +14679,7 @@ function ac_node_click$3(gobj, event, kw, src) {
14605
14679
  priv.anchor_name = node_data.full_name || "";
14606
14680
  priv.anchor_state = "on";
14607
14681
  yui_graph_update_anchor(gobj_read_attr(gobj, "$container"), priv.anchor_state);
14682
+ set_picking_mode(gobj, false);
14608
14683
  gobj_post_event(gobj, "EV_CENTER_ANCHOR", {}, gobj);
14609
14684
  return 0;
14610
14685
  }
@@ -37600,7 +37675,7 @@ Text.PARSED_STYLE_LIST = new Set([].concat(_toConsumableArray(DisplayObject.PARS
37600
37675
  * * register property @see https://developer.mozilla.org/en-US/docs/Web/API/CSS/RegisterProperty
37601
37676
  * * CSS Layout API
37602
37677
  */
37603
- var CSS = {
37678
+ var CSS$1 = {
37604
37679
  /**
37605
37680
  * <number>
37606
37681
  * @see https://drafts.csswg.org/css-values-4/#number-value
@@ -47649,7 +47724,7 @@ var e = 1e-4;
47649
47724
  syntax: PropertySyntax.ANGLE
47650
47725
  }
47651
47726
  ].forEach(function(property) {
47652
- CSS.registerProperty(property);
47727
+ CSS$1.registerProperty(property);
47653
47728
  });
47654
47729
  var polarToCartesian = function polarToCartesian(centerX, centerY, radius, angleInRadian) {
47655
47730
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.23.25",
3
+ "version": "7.23.26",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",
@@ -90,6 +90,20 @@ SDATA(data_type_t.DTP_INTEGER, "collapse_threshold", 0, 10, "Auto-collapse a no
90
90
  SDATA_END()
91
91
  ];
92
92
 
93
+ /*
94
+ * What the graph listens for while you are READING it, and while you
95
+ * are PICKING the node to anchor.
96
+ *
97
+ * The difference is `drag-element`: with it on, a click that drifts
98
+ * two pixels -- which is every click a hand makes -- becomes a drag,
99
+ * G6 fires no `node:click`, and the pick silently does not happen.
100
+ * Swapped with `setBehaviors()` and not with a behavior's `enable`,
101
+ * which REPLACES the behavior's own default test rather than adding
102
+ * to it.
103
+ */
104
+ const BEHAVIORS_READING = ['drag-canvas', 'zoom-canvas', 'drag-element'];
105
+ const BEHAVIORS_PICKING = ['drag-canvas', 'zoom-canvas'];
106
+
93
107
  let PRIVATE_DATA = {
94
108
  canvas_id: "",
95
109
  graph: null,
@@ -654,17 +668,7 @@ function build_graph(gobj)
654
668
 
655
669
  layout: layout_cfg.g6_layout,
656
670
 
657
- behaviors: [
658
- 'drag-canvas',
659
- 'zoom-canvas',
660
- /* Move a card by dragging it. The position is not kept --
661
- * this tree is rebuilt from the live gobj tree on every
662
- * refresh -- and it is still worth having: pulling two
663
- * cards apart to read the lines between them is the whole
664
- * use of it. `enable` REPLACES a behavior's default rather
665
- * than adding to it, so it is not passed. */
666
- 'drag-element',
667
- ],
671
+ behaviors: BEHAVIORS_READING.slice(),
668
672
  });
669
673
 
670
674
  if(priv.theme) {
@@ -2014,6 +2018,24 @@ function ac_center_anchor(gobj, event, kw, src)
2014
2018
  return 0;
2015
2019
  }
2016
2020
 
2021
+ /************************************************************
2022
+ * Reading, or picking the node to anchor.
2023
+ ************************************************************/
2024
+ function set_picking_mode(gobj, picking)
2025
+ {
2026
+ let graph = gobj.priv.graph;
2027
+
2028
+ if(graph && typeof graph.setBehaviors === "function") {
2029
+ graph.setBehaviors((picking? BEHAVIORS_PICKING: BEHAVIORS_READING).slice());
2030
+ }
2031
+
2032
+ let $container = gobj_read_attr(gobj, "$container");
2033
+ let $mount = $container? $container.querySelector('.gobj-tree-container'): null;
2034
+ if($mount) {
2035
+ $mount.classList.toggle('GOBJ_TREE_PICKING', !!picking);
2036
+ }
2037
+ }
2038
+
2017
2039
  /************************************************************
2018
2040
  * Arm the anchor, or let it go.
2019
2041
  *
@@ -2035,6 +2057,7 @@ function ac_toggle_anchor(gobj, event, kw, src)
2035
2057
  }
2036
2058
 
2037
2059
  yui_graph_update_anchor(gobj_read_attr(gobj, "$container"), priv.anchor_state);
2060
+ set_picking_mode(gobj, priv.anchor_state === "arming");
2038
2061
  return 0;
2039
2062
  }
2040
2063
 
@@ -2139,6 +2162,7 @@ function ac_node_click(gobj, event, kw, src)
2139
2162
  priv.anchor_name = node_data.full_name || "";
2140
2163
  priv.anchor_state = "on";
2141
2164
  yui_graph_update_anchor(gobj_read_attr(gobj, "$container"), priv.anchor_state);
2165
+ set_picking_mode(gobj, false);
2142
2166
 
2143
2167
  /* POSTED, not made here: a camera move issued inside G6's click
2144
2168
  * dispatch is swallowed -- see the note in yui_graph_center_on.
@@ -293,6 +293,38 @@
293
293
  z-index: 1;
294
294
  }
295
295
 
296
+ /*
297
+ * Picking the node to anchor. The pointer says a click is expected --
298
+ * without it the only sign the graph is waiting for one is a button
299
+ * at the far end of a toolbar.
300
+ */
301
+ .C_YUI_JSON .json-graph-container.JSON_GRAPH_PICKING,
302
+ .C_YUI_JSON .json-graph-container.JSON_GRAPH_PICKING * {
303
+ cursor: crosshair;
304
+ }
305
+
306
+ /*
307
+ * The card the camera is holding.
308
+ *
309
+ * It has to say so ON THE CARD: the toolbar button knows an anchor is
310
+ * set, and knowing WHICH node it is was left to the reader remembering
311
+ * what they clicked -- which is not a mark, it is a memory test.
312
+ *
313
+ * An outline and not a fill: the card's own colours mean things (a
314
+ * dashed border is a dict, a solid one a list, the header carries the
315
+ * group's hue), and a mark that repaints any of them would be saying
316
+ * two things with one channel. `outline` also draws OUTSIDE the box,
317
+ * so it cannot move a single row.
318
+ *
319
+ * Amber, the same "this one, right now" the toolbar's arming state
320
+ * uses. It is not one of the palette's action colours because it is
321
+ * not an action.
322
+ */
323
+ .C_YUI_JSON .JSON_CARD_ANCHORED {
324
+ outline: 3px solid #fa8c16;
325
+ outline-offset: 2px;
326
+ }
327
+
296
328
  /*
297
329
  * The graph mount, once its cards can be DRAGGED.
298
330
  *
@@ -692,24 +692,7 @@ function build_graph(gobj)
692
692
 
693
693
  layout: layout_cfg.g6_layout,
694
694
 
695
- behaviors: [
696
- 'drag-canvas',
697
- 'zoom-canvas',
698
- /*
699
- * Move a card by dragging it. The position is NOT kept:
700
- * the graph is rebuilt from the document on every refresh,
701
- * fold and layout change, and there is nothing here to
702
- * save it to -- this is a viewer over a value somebody
703
- * handed it, not a document of its own. Deliberate: being
704
- * able to pull two cards apart to read the lines between
705
- * them is worth having even when it lasts one session.
706
- *
707
- * No `enable`: a behavior's `enable` REPLACES the default,
708
- * it does not add to it, and the default here is exactly
709
- * what is wanted.
710
- */
711
- 'drag-element',
712
- ],
695
+ behaviors: BEHAVIORS_READING.slice(),
713
696
  });
714
697
 
715
698
  if(priv.theme) {
@@ -899,6 +882,23 @@ function build_cell_html(key, value, type, dark, matched, fold)
899
882
  ************************************************************/
900
883
  const FOLD_SPACER = `<span style="width:24px; flex:0 0 auto;"></span>`;
901
884
 
885
+ /*
886
+ * What the graph listens for while you are READING it, and while you
887
+ * are PICKING the node to anchor.
888
+ *
889
+ * The difference is `drag-element`, and dropping it is not a detail:
890
+ * with it on, a click that drifts two pixels -- which is every click a
891
+ * hand makes -- becomes a drag, G6 fires no `node:click`, and the pick
892
+ * silently does not happen. Measured: an instant click anchors, the
893
+ * same click with 2px of movement does not.
894
+ *
895
+ * Swapped with `setBehaviors()` and not with a behavior's `enable`,
896
+ * which REPLACES the behavior's own default test rather than adding to
897
+ * it -- the trap that made a card drag pan the canvas in 7.23.10.
898
+ */
899
+ const BEHAVIORS_READING = ['drag-canvas', 'zoom-canvas', 'drag-element'];
900
+ const BEHAVIORS_PICKING = ['drag-canvas', 'zoom-canvas'];
901
+
902
902
  /*
903
903
  * The card's geometry, in ONE place.
904
904
  *
@@ -1152,8 +1152,21 @@ function build_json_nodes(gobj, path, kw, nodes, edges, parent_id, parent_port)
1152
1152
  let min_width = Math.max(180, label.length * 9);
1153
1153
  let card_height = CARD_HEADER_H + lines.length * CARD_ROW_H;
1154
1154
 
1155
+ /*
1156
+ * The card carries its NAME and its PLACE in the document.
1157
+ *
1158
+ * `JSON_CARD` because a gclass that builds DOM has to leave a tree
1159
+ * somebody can read in the Inspector, and until now every card here
1160
+ * was an anonymous `<div>` among the anonymous `<div>`s G6 stacks.
1161
+ *
1162
+ * `data-json-path` because the anchor has to be able to find the
1163
+ * card it is holding: G6 paints no state style on an html node, so
1164
+ * the mark cannot be a node state and has to be a class on this
1165
+ * element -- and the path is what survives a rebuild, where the
1166
+ * node id does not.
1167
+ */
1155
1168
  let node_html = `
1156
- <div style="
1169
+ <div class="JSON_CARD" data-json-path="${escapeHtml(path)}" style="
1157
1170
  min-width: ${min_width}px;
1158
1171
  background: ${colors.bg};
1159
1172
  border: ${border_width}px ${is_dict ? 'dashed' : 'solid'} ${border_color};
@@ -1348,6 +1361,7 @@ function load_json(gobj)
1348
1361
  /* Ids are generated per build: point the anchor at its path
1349
1362
  * again before anybody asks the camera to go there. */
1350
1363
  reanchor(gobj);
1364
+ paint_anchor_mark(gobj);
1351
1365
 
1352
1366
  if(preserve_view) {
1353
1367
  yui_graph_update_zoom(gobj_read_attr(gobj, "$container"), priv.graph);
@@ -1820,6 +1834,65 @@ function reanchor(gobj)
1820
1834
  yui_graph_update_anchor(gobj_read_attr(gobj, "$container"), priv.anchor_state);
1821
1835
  }
1822
1836
 
1837
+ /************************************************************
1838
+ * Reading, or picking the node to anchor.
1839
+ *
1840
+ * Two visible consequences and one invisible: the cursor says
1841
+ * a click is expected, the mount says which mode it is in for
1842
+ * anyone reading the DOM, and node dragging stands aside so a
1843
+ * click that drifts is still a click.
1844
+ ************************************************************/
1845
+ function set_picking_mode(gobj, picking)
1846
+ {
1847
+ let priv = gobj.priv;
1848
+ let graph = priv.graph;
1849
+
1850
+ if(graph && typeof graph.setBehaviors === "function") {
1851
+ graph.setBehaviors((picking? BEHAVIORS_PICKING: BEHAVIORS_READING).slice());
1852
+ }
1853
+
1854
+ let $container = gobj_read_attr(gobj, "$container");
1855
+ if($container) {
1856
+ let $mount = $container.querySelector('.json-graph-container');
1857
+ if($mount) {
1858
+ $mount.classList.toggle('JSON_GRAPH_PICKING', !!picking);
1859
+ }
1860
+ }
1861
+ }
1862
+
1863
+ /************************************************************
1864
+ * Mark the card the camera is holding.
1865
+ *
1866
+ * A class on the card's own element and not a G6 node state:
1867
+ * G6 paints no state style on an html node, so `setElementState`
1868
+ * would select it correctly and show nothing.
1869
+ *
1870
+ * Re-applied after every rebuild, because the cards are new DOM
1871
+ * each time and the mark would otherwise survive only until the
1872
+ * next fold.
1873
+ ************************************************************/
1874
+ function paint_anchor_mark(gobj)
1875
+ {
1876
+ let priv = gobj.priv;
1877
+ let $container = gobj_read_attr(gobj, "$container");
1878
+
1879
+ if(!$container) {
1880
+ return;
1881
+ }
1882
+ for(let $card of $container.querySelectorAll('.JSON_CARD_ANCHORED')) {
1883
+ $card.classList.remove('JSON_CARD_ANCHORED');
1884
+ }
1885
+ if(priv.anchor_state !== "on" || !priv.anchor_path) {
1886
+ return;
1887
+ }
1888
+ let $it = $container.querySelector(
1889
+ '.JSON_CARD[data-json-path="' + CSS.escape(priv.anchor_path) + '"]'
1890
+ );
1891
+ if($it) {
1892
+ $it.classList.add('JSON_CARD_ANCHORED');
1893
+ }
1894
+ }
1895
+
1823
1896
  /************************************************************
1824
1897
  * Centre on the anchor, one cycle after it was chosen.
1825
1898
  ************************************************************/
@@ -1827,6 +1900,7 @@ function ac_center_anchor(gobj, event, kw, src)
1827
1900
  {
1828
1901
  let priv = gobj.priv;
1829
1902
 
1903
+ paint_anchor_mark(gobj);
1830
1904
  if(priv.anchor_state === "on" && priv.anchor_id) {
1831
1905
  yui_graph_center_on(priv.graph, priv.anchor_id);
1832
1906
  }
@@ -1854,6 +1928,8 @@ function ac_toggle_anchor(gobj, event, kw, src)
1854
1928
  }
1855
1929
 
1856
1930
  yui_graph_update_anchor(gobj_read_attr(gobj, "$container"), priv.anchor_state);
1931
+ paint_anchor_mark(gobj);
1932
+ set_picking_mode(gobj, priv.anchor_state === "arming");
1857
1933
  return 0;
1858
1934
  }
1859
1935
 
@@ -1945,6 +2021,7 @@ function ac_node_click(gobj, event, kw, src)
1945
2021
  priv.anchor_path = (nodedata && nodedata.data)? nodedata.data.path: "";
1946
2022
  priv.anchor_state = "on";
1947
2023
  yui_graph_update_anchor(gobj_read_attr(gobj, "$container"), priv.anchor_state);
2024
+ set_picking_mode(gobj, false);
1948
2025
 
1949
2026
  /*
1950
2027
  * The camera move is POSTED, not made here.
package/src/lib_graph.css CHANGED
@@ -256,6 +256,14 @@
256
256
  * pressed button hands it back to Bulma's rule and the toggle appears
257
257
  * to switch off under the pointer.
258
258
  */
259
+ /* Picking the node to anchor, in the gobj tree: the pointer says a
260
+ * click is expected, which is otherwise only announced by a button at
261
+ * the far end of a toolbar. */
262
+ .gobj-tree-container.GOBJ_TREE_PICKING,
263
+ .gobj-tree-container.GOBJ_TREE_PICKING * {
264
+ cursor: crosshair;
265
+ }
266
+
259
267
  .button.pressed_state,
260
268
  .button.pressed_state:hover {
261
269
  background-color: var(--bulma-text, #2e333d);
@@ -233,11 +233,35 @@ export function yui_graph_update_anchor($container, state)
233
233
  * an error worth a log line per notch, they are all "there is
234
234
  * nothing to centre right now".
235
235
  ************************************************************/
236
+ const __centring__ = new WeakMap();
237
+
236
238
  export async function yui_graph_center_on(graph, node_id)
237
239
  {
238
240
  if(!graph || !node_id) {
239
241
  return false;
240
242
  }
243
+
244
+ /*
245
+ * ONE centring at a time, per graph.
246
+ *
247
+ * This runs on every zoom notch, and one run is several awaited
248
+ * camera moves. A wheel gesture is a BURST of notches, so without
249
+ * this the runs overlap: each one measures a position another one
250
+ * is in the middle of changing, and they walk the camera around
251
+ * instead of converging -- which reads as a graph that pans and
252
+ * never centres.
253
+ *
254
+ * A request that arrives mid-run is not dropped, it is remembered:
255
+ * the last one wins and runs once at the end, which is the only
256
+ * one whose answer is still true.
257
+ */
258
+ let st = __centring__.get(graph);
259
+ if(st && st.running) {
260
+ st.again = node_id;
261
+ return true;
262
+ }
263
+ __centring__.set(graph, {running: true, again: null});
264
+
241
265
  try {
242
266
  if(typeof graph.getElementData === "function" && !graph.getElementData(node_id)) {
243
267
  return false;
@@ -289,6 +313,12 @@ export async function yui_graph_center_on(graph, node_id)
289
313
  return true;
290
314
  } catch(e) {
291
315
  return false; /* the element is gone, or the graph is between renders */
316
+ } finally {
317
+ let pending = __centring__.get(graph);
318
+ __centring__.set(graph, {running: false, again: null});
319
+ if(pending && pending.again) {
320
+ yui_graph_center_on(graph, pending.again);
321
+ }
292
322
  }
293
323
  }
294
324