@yuneta/gobj-ui 7.2.5 → 7.4.0

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
@@ -582,6 +582,15 @@ Two details that are not decoration:
582
582
  The find and the topic focus **share the highlight**: starting one clears the
583
583
  other. Two amber sets at once would say nothing about either.
584
584
 
585
+ The highlight is painted **into the card's own html**, not with G6's `active`
586
+ element state. That state is an amber `stroke` + `halo`, both properties of a
587
+ node's KEY SHAPE — and every node here is an `html` node, whose key shape is a
588
+ DOM element. There was nothing for either property to paint on, so the amber
589
+ had never appeared, for the topic focus either. Only the cards whose state
590
+ changes are repainted, and a theme switch carries the highlight across (it
591
+ rebuilds every card, and rebuilding them without it would clear what is on
592
+ screen).
593
+
585
594
  Wiring: the box sends `EV_FIND_NODES {text}` to the view, which forwards it to
586
595
  `C_G6_NODES_TREE`; the graph answers `EV_FIND_RESULT {term, matches}`, which the
587
596
  view declares like every other event its child publishes.
@@ -18594,6 +18594,8 @@ var PRIVATE_DATA$4 = {
18594
18594
  topics: [],
18595
18595
  records: {},
18596
18596
  gobj_nodes_tree: null,
18597
+ find_timer: null,
18598
+ focus_topic: "",
18597
18599
  gobj_treedb_tables: null,
18598
18600
  hook_data_viewer: null,
18599
18601
  json_gobj: null,
@@ -18668,6 +18670,11 @@ function mt_stop$4(gobj) {
18668
18670
  * Framework Method: Destroy
18669
18671
  ***************************************************************/
18670
18672
  function mt_destroy$4(gobj) {
18673
+ let priv = gobj.priv;
18674
+ if (priv.find_timer) {
18675
+ clearTimeout(priv.find_timer);
18676
+ priv.find_timer = null;
18677
+ }
18671
18678
  destroy_ui$1(gobj);
18672
18679
  }
18673
18680
  /***************************
@@ -18687,26 +18694,37 @@ function build_ui$4(gobj) {
18687
18694
  class: "C_YUI_TREEDB_GRAPH",
18688
18695
  style: `height:100%; display:flex; flex-direction:column;`
18689
18696
  },
18690
- [[
18691
- "div",
18692
- { class: "GRAPH_TOOLBAR_ROW is-flex-grow-0 is-flex is-align-items-center" },
18693
- $back ? [$back, $toolbar] : [$toolbar]
18694
- ], [
18695
- "div",
18696
- {
18697
- class: `GRAPH_BODY is-flex-grow-1 ${padding}`,
18698
- style: "height:100%; min-height:0; overflow:hidden;"
18699
- },
18700
- [[
18697
+ [
18698
+ [
18699
+ "div",
18700
+ { class: "GRAPH_TOOLBAR_ROW is-flex-grow-0 is-flex is-align-items-center" },
18701
+ $back ? [$back, $toolbar] : [$toolbar]
18702
+ ],
18703
+ [
18701
18704
  "div",
18702
18705
  {
18703
- id: priv.canvas_id,
18704
- class: `GRAPH_CANVAS graph-container`,
18705
- style: "height:100%; min-height:0;border: 1px solid var(--bulma-border-weak);border-radius:0.2rem;"
18706
+ class: "GRAPH_LEGEND is-hidden is-flex-grow-0",
18707
+ style: "display:flex; flex-wrap:wrap; align-items:center; gap:.4rem; padding:.35rem .5rem;"
18706
18708
  },
18707
18709
  []
18708
- ]]
18709
- ]]
18710
+ ],
18711
+ [
18712
+ "div",
18713
+ {
18714
+ class: `GRAPH_BODY is-flex-grow-1 ${padding}`,
18715
+ style: "height:100%; min-height:0; overflow:hidden;"
18716
+ },
18717
+ [[
18718
+ "div",
18719
+ {
18720
+ id: priv.canvas_id,
18721
+ class: `GRAPH_CANVAS graph-container`,
18722
+ style: "height:100%; min-height:0;border: 1px solid var(--bulma-border-weak);border-radius:0.2rem;"
18723
+ },
18724
+ []
18725
+ ]]
18726
+ ]
18727
+ ]
18710
18728
  ]);
18711
18729
  (0, _yuneta_gobj_js.gobj_write_attr)(gobj, "$container", $container);
18712
18730
  (0, _yuneta_gobj_js.refresh_language)($container, i18next.t);
@@ -18774,7 +18792,7 @@ function destroy_ui$1(gobj) {
18774
18792
  *
18775
18793
  ************************************************************/
18776
18794
  function make_toolbar(gobj) {
18777
- gobj.priv;
18795
+ let priv = gobj.priv;
18778
18796
  let modes = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "operation_modes");
18779
18797
  if ((0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "readonly")) modes = modes.filter((mode) => mode !== "edition");
18780
18798
  let left_items = [
@@ -18839,6 +18857,29 @@ function make_toolbar(gobj) {
18839
18857
  (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_REFRESH_TREEDB", { evt }, gobj);
18840
18858
  } }
18841
18859
  ],
18860
+ [
18861
+ "button",
18862
+ {
18863
+ class: "GRAPH_LEGEND_BTN button ml-2",
18864
+ title: (0, i18next.t)("legend"),
18865
+ "aria-label": (0, i18next.t)("legend"),
18866
+ "data-i18n-title": "legend",
18867
+ "data-i18n-aria-label": "legend"
18868
+ },
18869
+ [["i", { class: "yi-square" }], [
18870
+ "span",
18871
+ {
18872
+ class: "is-hidden-mobile",
18873
+ style: "padding-left:5px;",
18874
+ i18n: "legend"
18875
+ },
18876
+ "legend"
18877
+ ]],
18878
+ { click: (evt) => {
18879
+ evt.stopPropagation();
18880
+ (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_TOGGLE_LEGEND", {}, gobj);
18881
+ } }
18882
+ ],
18842
18883
  [
18843
18884
  "button",
18844
18885
  {
@@ -18883,7 +18924,12 @@ function make_toolbar(gobj) {
18883
18924
  ]],
18884
18925
  { input: (evt) => {
18885
18926
  evt.stopPropagation();
18886
- (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_FIND_NODES", { text: evt.target.value.trim() }, gobj);
18927
+ let text = evt.target.value.trim();
18928
+ if (priv.find_timer) clearTimeout(priv.find_timer);
18929
+ priv.find_timer = setTimeout(function() {
18930
+ priv.find_timer = null;
18931
+ (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_FIND_NODES", { text }, gobj);
18932
+ }, 250);
18887
18933
  } }
18888
18934
  ], [
18889
18935
  "div",
@@ -19843,6 +19889,86 @@ function ac_set_operation_mode$1(gobj, event, kw, src) {
19843
19889
  * until its data is loaded).
19844
19890
  ************************************************************/
19845
19891
  /************************************************************
19892
+ * Fill the legend strip with one entry per topic: a swatch in the
19893
+ * topic's colour and its name. The colours belong to the graph child —
19894
+ * it assigns them from its palette when the schema arrives — so they
19895
+ * are read from there and never guessed twice.
19896
+ *
19897
+ * An entry is a BUTTON: clicking it focuses that topic, clicking the
19898
+ * focused one clears the focus. The focus travels the same way a topic
19899
+ * card's graph icon travels — as EV_TOPIC_SELECTED, which the host turns
19900
+ * into the URL, so what you are looking at stays linkable.
19901
+ ************************************************************/
19902
+ function refresh_legend(gobj) {
19903
+ let priv = gobj.priv;
19904
+ let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
19905
+ if (!$container) return;
19906
+ let $legend = $container.querySelector(".GRAPH_LEGEND");
19907
+ if (!$legend) return;
19908
+ let descs = priv.gobj_nodes_tree ? (0, _yuneta_gobj_js.gobj_read_attr)(priv.gobj_nodes_tree, "descs") : null;
19909
+ $legend.textContent = "";
19910
+ if (!descs) return;
19911
+ for (const [topic_name, desc] of Object.entries(descs)) {
19912
+ if (topic_name.substring(0, 2) === "__") continue;
19913
+ if (!desc || !desc.color) continue;
19914
+ let focused = priv.focus_topic === topic_name;
19915
+ let $item = (0, _yuneta_gobj_js.createElement2)([
19916
+ "button",
19917
+ {
19918
+ class: "GRAPH_LEGEND_ITEM button is-small" + (focused ? " is-primary" : ""),
19919
+ title: topic_name,
19920
+ "aria-label": topic_name,
19921
+ "aria-pressed": focused ? "true" : "false"
19922
+ },
19923
+ [["span", {
19924
+ class: "GRAPH_LEGEND_SWATCH",
19925
+ style: `display:inline-block; width:.8rem; height:.8rem; border-radius:3px; margin-right:.4rem; background:${desc.color}; border:1px solid rgba(0,0,0,.25);`
19926
+ }], [
19927
+ "span",
19928
+ {},
19929
+ topic_name
19930
+ ]],
19931
+ { click: (evt) => {
19932
+ evt.stopPropagation();
19933
+ (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_LEGEND_TOPIC", { topic: topic_name }, gobj);
19934
+ } }
19935
+ ]);
19936
+ $legend.appendChild($item);
19937
+ }
19938
+ }
19939
+ /************************************************************
19940
+ *
19941
+ ************************************************************/
19942
+ function ac_toggle_legend(gobj, event, kw, src) {
19943
+ let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
19944
+ if (!$container) return 0;
19945
+ let $legend = $container.querySelector(".GRAPH_LEGEND");
19946
+ if (!$legend) {
19947
+ (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no legend strip to toggle`);
19948
+ return -1;
19949
+ }
19950
+ if ($legend.classList.contains("is-hidden")) {
19951
+ refresh_legend(gobj);
19952
+ $legend.classList.remove("is-hidden");
19953
+ } else $legend.classList.add("is-hidden");
19954
+ return 0;
19955
+ }
19956
+ /************************************************************
19957
+ * A legend entry was clicked: focus that topic, or clear the focus if
19958
+ * it was already the focused one. Published UP rather than applied
19959
+ * here, so the URL follows — the host owns the route.
19960
+ ************************************************************/
19961
+ function ac_legend_topic(gobj, event, kw, src) {
19962
+ let priv = gobj.priv;
19963
+ let topic = kw && kw.topic || "";
19964
+ if (!topic) {
19965
+ (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: legend click with no topic`);
19966
+ return -1;
19967
+ }
19968
+ (0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_TOPIC_SELECTED", { topic: priv.focus_topic === topic ? "" : topic });
19969
+ return 0;
19970
+ }
19971
+ /************************************************************
19846
19972
  * Forward the find down to the graph child.
19847
19973
  ************************************************************/
19848
19974
  function ac_find_nodes$1(gobj, event, kw, src) {
@@ -19871,7 +19997,11 @@ function ac_find_result(gobj, event, kw, src) {
19871
19997
  }
19872
19998
  function ac_set_focus_topic(gobj, event, kw, src) {
19873
19999
  let priv = gobj.priv;
19874
- if (priv.gobj_nodes_tree) (0, _yuneta_gobj_js.gobj_send_event)(priv.gobj_nodes_tree, "EV_FOCUS_TOPIC", { topic: kw && kw.topic }, gobj);
20000
+ priv.focus_topic = kw && kw.topic || "";
20001
+ if (priv.gobj_nodes_tree) (0, _yuneta_gobj_js.gobj_send_event)(priv.gobj_nodes_tree, "EV_FOCUS_TOPIC", { topic: priv.focus_topic }, gobj);
20002
+ let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
20003
+ let $legend = $container ? $container.querySelector(".GRAPH_LEGEND") : null;
20004
+ if ($legend && !$legend.classList.contains("is-hidden")) refresh_legend(gobj);
19875
20005
  return 0;
19876
20006
  }
19877
20007
  /************************************************************
@@ -20039,6 +20169,16 @@ function create_gclass$4(gclass_name) {
20039
20169
  ac_find_nodes$1,
20040
20170
  null
20041
20171
  ],
20172
+ [
20173
+ "EV_TOGGLE_LEGEND",
20174
+ ac_toggle_legend,
20175
+ null
20176
+ ],
20177
+ [
20178
+ "EV_LEGEND_TOPIC",
20179
+ ac_legend_topic,
20180
+ null
20181
+ ],
20042
20182
  [
20043
20183
  "EV_FIND_RESULT",
20044
20184
  ac_find_result,
@@ -20087,6 +20227,9 @@ function create_gclass$4(gclass_name) {
20087
20227
  ["EV_SET_FOCUS_TOPIC", 0],
20088
20228
  ["EV_FIND_NODES", 0],
20089
20229
  ["EV_FIND_RESULT", 0],
20230
+ ["EV_TOGGLE_LEGEND", 0],
20231
+ ["EV_LEGEND_TOPIC", 0],
20232
+ ["EV_TOPIC_SELECTED", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT | _yuneta_gobj_js.event_flag_t.EVF_NO_WARN_SUBS],
20090
20233
  ["EV_OPERATION_MODE_CHANGED", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT | _yuneta_gobj_js.event_flag_t.EVF_NO_WARN_SUBS],
20091
20234
  ["EV_RECORD_WRITTEN", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT | _yuneta_gobj_js.event_flag_t.EVF_NO_WARN_SUBS],
20092
20235
  ["EV_SHOW", 0],
@@ -52642,6 +52785,8 @@ ensure_drag_canvas_patch();
52642
52785
  * Constants
52643
52786
  ***************************************************************/
52644
52787
  var GCLASS_NAME$1 = "C_G6_NODES_TREE";
52788
+ var HIGHLIGHT_COLOR = "#f0a020";
52789
+ var HIGHLIGHT_HALO = "rgba(240,160,32,0.35)";
52645
52790
  /***************************************************************
52646
52791
  * Internal layout and operation mode definitions
52647
52792
  ***************************************************************/
@@ -52691,6 +52836,7 @@ var attrs_table$1 = [
52691
52836
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_gridline", 0, true, "Use gridline plugin"),
52692
52837
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_fullscreen", 0, true, "Use fullscreen plugin"),
52693
52838
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_toolbar", 0, true, "Use toolbar plugin"),
52839
+ (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_INTEGER, "minimap_min_nodes", 0, 30, "Show the minimap from this many nodes on (0 = never). A minimap of a graph that fits on screen is decoration; one of two hundred cards is the only way to know where you are"),
52694
52840
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "toolbar_position", 0, "right-top", "Toolbar position: top-left, top-right, bottom-left, bottom-right, left-top, right-top"),
52695
52841
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_LIST, "layout_names", _yuneta_gobj_js.sdata_flag_t.SDF_RD, JSON.stringify(Object.keys(_layouts)), "Available layout names (read-only, for parent to query)"),
52696
52842
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "hook_port_position", 0, "bottom", "Hook port position"),
@@ -53918,10 +54064,12 @@ function graph_focus_topic(gobj, topic) {
53918
54064
  if (ids.length === 0) (0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: focus topic '${topic}' has no nodes`);
53919
54065
  for (let id of ids) states[id] = ["active"];
53920
54066
  }
54067
+ let prev_ids = priv._focus_ids || [];
53921
54068
  priv._focus_ids = ids;
53922
54069
  priv._focus_topic = topic || null;
53923
54070
  try {
53924
54071
  if (typeof graph.setElementState === "function") graph.setElementState(states);
54072
+ apply_node_highlight(gobj, prev_ids, ids);
53925
54073
  if (ids.length && typeof graph.focusElement === "function") graph.focusElement(ids);
53926
54074
  } catch (e) {
53927
54075
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: focus topic apply failed: ${e}`);
@@ -53978,10 +54126,12 @@ function graph_find_nodes(gobj, term) {
53978
54126
  }
53979
54127
  for (let id of ids) states[id] = ["active"];
53980
54128
  }
54129
+ let prev_ids = priv._focus_ids || [];
53981
54130
  priv._focus_ids = ids;
53982
54131
  priv._focus_topic = null;
53983
54132
  try {
53984
54133
  if (typeof graph.setElementState === "function") graph.setElementState(states);
54134
+ apply_node_highlight(gobj, prev_ids, ids);
53985
54135
  if (ids.length && typeof graph.focusElement === "function") graph.focusElement(ids);
53986
54136
  } catch (e) {
53987
54137
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: find apply failed: ${e}`);
@@ -55525,27 +55675,121 @@ function show_node_detail_popover(gobj, node_id) {
55525
55675
  * not re-themed by setTheme()) are regenerated; structural
55526
55676
  * junction diamonds get their neutral fill/stroke re-themed.
55527
55677
  ************************************************************/
55528
- function refresh_html_nodes_theme(gobj, theme) {
55678
+ /************************************************************
55679
+ * Show or hide the minimap, deciding by the SIZE of the graph.
55680
+ *
55681
+ * A minimap of a graph that already fits on screen is decoration; one
55682
+ * of two hundred cards is the only way to know where you are. So it is
55683
+ * not a preference the reader has to find and set — it appears when
55684
+ * there is something to be lost in, from `minimap_min_nodes` on.
55685
+ *
55686
+ * Its shapes are drawn by hand. G6's minimap clones each element's key
55687
+ * shape into its own canvas, and every node here is an `html` node
55688
+ * whose key shape is a DOM element — the same reason the `active`
55689
+ * state never painted (see HIGHLIGHT_COLOR). A block in the topic's
55690
+ * colour is also what a minimap of cards SHOULD show: at that scale a
55691
+ * card is a rectangle anyway.
55692
+ ************************************************************/
55693
+ function refresh_minimap(gobj) {
55529
55694
  let graph = gobj.priv.graph;
55530
55695
  if (!graph) return;
55696
+ let threshold = (0, _yuneta_gobj_js.gobj_read_integer_attr)(gobj, "minimap_min_nodes");
55697
+ let n = 0;
55698
+ try {
55699
+ let data = graph.getData() || {};
55700
+ n = (0, _yuneta_gobj_js.is_array)(data.nodes) ? data.nodes.length : 0;
55701
+ } catch (e) {
55702
+ n = 0;
55703
+ }
55704
+ if (!threshold || n < threshold) {
55705
+ graph_remove_plugin(gobj, "minimap");
55706
+ return;
55707
+ }
55708
+ if (graph_get_plugin(gobj, "minimap")) return;
55709
+ graph_add_plugin(gobj, "minimap", {
55710
+ size: [200, 140],
55711
+ position: "bottom-left",
55712
+ shape: (id, element_type, element) => {
55713
+ if (element_type !== "node") return element;
55714
+ try {
55715
+ let nd = graph.getNodeData(id);
55716
+ let size = nd && nd.style && nd.style.size || [120, 60];
55717
+ let color = nd && nd.data && nd.data.desc && nd.data.desc.color || "#94a3b8";
55718
+ return new Rect({ style: {
55719
+ x: -size[0] / 2,
55720
+ y: -size[1] / 2,
55721
+ width: size[0],
55722
+ height: size[1],
55723
+ fill: color,
55724
+ radius: 4
55725
+ } });
55726
+ } catch (e) {
55727
+ (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: minimap shape failed: ${e}`);
55728
+ return element;
55729
+ }
55730
+ }
55731
+ });
55732
+ }
55733
+ /************************************************************
55734
+ * The innerHTML of ONE node, in the given theme and highlight state.
55735
+ * The three treedb tiers (hierarchical / extended / child) each have
55736
+ * their own card, and both the theme refresh and the highlight need the
55737
+ * same three-way choice — it lived inline in the theme refresh and is
55738
+ * shared now. Returns null for a node that carries no desc.
55739
+ ************************************************************/
55740
+ function node_innerHTML_of(nd, theme, highlight) {
55741
+ if (!nd || !nd.data || !nd.data.desc) return null;
55742
+ let desc = nd.data.desc;
55743
+ let record = nd.data.record || {};
55744
+ let label = node_label(desc, record);
55745
+ switch (desc.node_treedb_type) {
55746
+ case "child": return build_chip_innerHTML(desc.color, theme, record.icon, label, record.id, highlight);
55747
+ case "extended": return build_node_innerHTML(desc.color, theme, record.icon, label, desc.topic_name, true, record.id, highlight);
55748
+ case "hierarchical": return build_node_innerHTML(desc.color, theme, record.icon, label, desc.topic_name, false, record.id, highlight);
55749
+ }
55750
+ return null;
55751
+ }
55752
+ /************************************************************
55753
+ * Repaint the cards whose highlight state CHANGES: the ones that had it
55754
+ * and lose it, plus the ones that gain it. Only those — a treedb graph
55755
+ * is redrawn per keystroke of the find box otherwise.
55756
+ ************************************************************/
55757
+ function apply_node_highlight(gobj, prev_ids, next_ids) {
55758
+ let priv = gobj.priv;
55759
+ let graph = priv.graph;
55760
+ if (!graph) return;
55761
+ let next = new Set(next_ids || []);
55762
+ let touched = /* @__PURE__ */ new Set([...prev_ids || [], ...next]);
55763
+ if (touched.size === 0) return;
55764
+ let updates = [];
55765
+ for (let id of touched) {
55766
+ let html = node_innerHTML_of(graph.getNodeData(id), priv.theme, next.has(id));
55767
+ if (html !== null) updates.push({
55768
+ id,
55769
+ style: { innerHTML: html }
55770
+ });
55771
+ }
55772
+ if (!updates.length) return;
55773
+ try {
55774
+ graph.updateNodeData(updates);
55775
+ graph.draw();
55776
+ } catch (e) {
55777
+ (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: cannot repaint the highlight: ${e}`);
55778
+ }
55779
+ }
55780
+ function refresh_html_nodes_theme(gobj, theme) {
55781
+ let priv = gobj.priv;
55782
+ let graph = priv.graph;
55783
+ if (!graph) return;
55531
55784
  let nodes = graph.getData().nodes || [];
55785
+ let highlighted = new Set(priv._focus_ids || []);
55532
55786
  let updates = [];
55533
55787
  for (let i = 0; i < nodes.length; i++) {
55534
- let nd = graph.getNodeData(nodes[i].id);
55535
- if (!nd || !nd.data || !nd.data.desc) continue;
55536
- let tt = nd.data.desc.node_treedb_type;
55537
- let record = nd.data.record || {};
55538
- if (tt === "hierarchical") updates.push({
55539
- id: nodes[i].id,
55540
- style: { innerHTML: build_node_innerHTML(nd.data.desc.color, theme, record.icon, node_label(nd.data.desc, record), nd.data.desc.topic_name, false, record.id) }
55541
- });
55542
- else if (tt === "child") updates.push({
55543
- id: nodes[i].id,
55544
- style: { innerHTML: build_chip_innerHTML(nd.data.desc.color, theme, record.icon, node_label(nd.data.desc, record), record.id) }
55545
- });
55546
- else if (tt === "extended") updates.push({
55547
- id: nodes[i].id,
55548
- style: { innerHTML: build_node_innerHTML(nd.data.desc.color, theme, record.icon, node_label(nd.data.desc, record), nd.data.desc.topic_name, true, record.id) }
55788
+ let id = nodes[i].id;
55789
+ let html = node_innerHTML_of(graph.getNodeData(id), theme, highlighted.has(id));
55790
+ if (html !== null) updates.push({
55791
+ id,
55792
+ style: { innerHTML: html }
55549
55793
  });
55550
55794
  }
55551
55795
  if (updates.length > 0) graph.updateNodeData(updates);
@@ -55577,12 +55821,13 @@ function refresh_default_edges_theme(gobj, theme) {
55577
55821
  * but lighter (1px border, no shadow, single line). The name is
55578
55822
  * always legible (ellipsis + native title tooltip on overflow).
55579
55823
  ************************************************************/
55580
- function build_chip_innerHTML(color, theme, icon, label, key) {
55824
+ function build_chip_innerHTML(color, theme, icon, label, key, highlight) {
55581
55825
  let title = key || label;
55582
55826
  let dark = theme === "dark";
55583
55827
  let bg = dark ? `color-mix(in srgb, ${color} 30%, #2c3542)` : `color-mix(in srgb, ${color} 10%, ${dark ? "#1b2230" : "#ffffff"})`;
55584
55828
  let border = dark ? `color-mix(in srgb, ${color} 85%, #ffffff)` : color;
55585
55829
  let text_color = dark ? "#e8eaed" : "#0f172a";
55830
+ if (highlight) border = HIGHLIGHT_COLOR;
55586
55831
  let icon_html = "";
55587
55832
  if (icon) icon_html = `<img src="${(0, _yuneta_gobj_js.safeSrc)(icon)}" alt="" style="
55588
55833
  width: 16px; height: 16px; object-fit: contain;
@@ -55594,7 +55839,8 @@ function build_chip_innerHTML(color, theme, icon, label, key) {
55594
55839
  width: 100%;
55595
55840
  height: 100%;
55596
55841
  background: ${bg};
55597
- border: 1px solid ${border};
55842
+ border: ${highlight ? "3px" : "1px"} solid ${border};
55843
+ ${highlight ? `box-shadow: 0 0 0 4px ${HIGHLIGHT_HALO};` : ""}
55598
55844
  border-radius: 8px;
55599
55845
  color: ${text_color};
55600
55846
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
@@ -55620,7 +55866,7 @@ function build_chip_innerHTML(color, theme, icon, label, key) {
55620
55866
  * colour is kept (per-topic differentiation) but softened via
55621
55867
  * color-mix instead of a harsh saturated fill. Theme-aware.
55622
55868
  ************************************************************/
55623
- function build_node_innerHTML(color, theme, icon, label, topic_name, structural, key) {
55869
+ function build_node_innerHTML(color, theme, icon, label, topic_name, structural, key, highlight) {
55624
55870
  let title = key || label;
55625
55871
  let dark = theme === "dark";
55626
55872
  let surface = dark ? "#1b2230" : "#ffffff";
@@ -55634,6 +55880,10 @@ function build_node_innerHTML(color, theme, icon, label, topic_name, structural,
55634
55880
  border = dark ? `color-mix(in srgb, ${color} 85%, #ffffff)` : color;
55635
55881
  border_style = "solid";
55636
55882
  }
55883
+ if (highlight) {
55884
+ border = HIGHLIGHT_COLOR;
55885
+ border_style = "solid";
55886
+ }
55637
55887
  let title_color = dark ? "#e8eaed" : "#0f172a";
55638
55888
  let sub_color = dark ? "#9aa4b2" : "#64748b";
55639
55889
  let shadow = dark ? "0 1px 3px rgba(0,0,0,0.45), 0 1px 2px rgba(0,0,0,0.30)" : "0 1px 3px rgba(15,23,42,0.12), 0 1px 2px rgba(15,23,42,0.06)";
@@ -55656,9 +55906,9 @@ function build_node_innerHTML(color, theme, icon, label, topic_name, structural,
55656
55906
  width: 100%;
55657
55907
  height: 100%;
55658
55908
  background: ${bg};
55659
- border: 1.5px ${border_style} ${border};
55909
+ border: ${highlight ? "3px" : "1.5px"} ${border_style} ${border};
55660
55910
  border-radius: 10px;
55661
- box-shadow: ${shadow};
55911
+ box-shadow: ${highlight ? `0 0 0 4px ${HIGHLIGHT_HALO}, ${shadow}` : shadow};
55662
55912
  color: ${title_color};
55663
55913
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
55664
55914
  display: flex;
@@ -56277,6 +56527,7 @@ function ac_load_data(gobj, event, kw, src) {
56277
56527
  graph_layout(gobj).then(() => {
56278
56528
  if (priv.edit_mode) graph_add_plugin(gobj, "history");
56279
56529
  else graph_remove_plugin(gobj, "history");
56530
+ refresh_minimap(gobj);
56280
56531
  if (priv._pending_focus_topic !== null) {
56281
56532
  let ft = priv._pending_focus_topic;
56282
56533
  priv._pending_focus_topic = null;