@yuneta/gobj-ui 5.16.0 → 5.17.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.
@@ -19754,11 +19754,26 @@ function register_c_yui_treedb_graph() {
19754
19754
  /***********************************************************************
19755
19755
  * c_yui_treedb_schema.js
19756
19756
  *
19757
- * Schema-graph landing (prototype): the treedb drawn as a GRAPH OF
19758
- * TOPICS one node per topic, one edge per hook/fkey relationship
19759
- * from the schema `descs` alone (no data, no backend calls). A
19760
- * node click opens that topic's table (a real hash navigation via
19761
- * the host-supplied `node_route`). An alternate landing to the
19757
+ * Schema-graph landing: the treedb drawn the way its `.c` literal
19758
+ * draws it in ASCII (treedb_schema_*.c, treedb_system_schema.c)
19759
+ * one CARD per topic listing its fields in schema order, one edge
19760
+ * per hook, from the row that declares the hook to the fkey row of
19761
+ * the child it names. Built from the schema `descs` alone: no data,
19762
+ * no backend calls.
19763
+ *
19764
+ * WHY THE CARD AND NOT A DOT. A topic is its fields; a schema is
19765
+ * read to find out what a topic holds and what links to what. A
19766
+ * graph of labelled dots answers neither, and the node graph next
19767
+ * door (C_G6_NODES_TREE) answers a different question entirely —
19768
+ * it draws the RECORDS, so on a treedb whose records are schemas
19769
+ * it draws one box per column, hundreds of them, each labelled by
19770
+ * a pkey that may be a rowid. This view draws the schema itself.
19771
+ *
19772
+ * The marks are the notation of the `.c` literals, so the drawing
19773
+ * and the source read the same — see schema_rows().
19774
+ *
19775
+ * A node click opens that topic's table (a real hash navigation
19776
+ * via the host-supplied `node_route`). An alternate landing to the
19762
19777
  * topic cards, in the spirit of "every treedb is a graph".
19763
19778
  *
19764
19779
  * Copyright (c) 2026, ArtGins.
@@ -19768,6 +19783,27 @@ function register_c_yui_treedb_graph() {
19768
19783
  * Constants
19769
19784
  ***************************************************************/
19770
19785
  var GCLASS_NAME$2 = "C_YUI_TREEDB_SCHEMA";
19786
+ /************************************************************
19787
+ * Geometry of a card, in one place: the row height is what
19788
+ * turns a field's index into the vertical position of its
19789
+ * port, so an edge leaves the very row that declares the
19790
+ * hook and lands on the row that declares the fkey.
19791
+ ************************************************************/
19792
+ var CARD_HEADER_H = 30;
19793
+ var CARD_ROW_H = 19;
19794
+ var CARD_PAD_V = 7;
19795
+ var CARD_MIN_W = 210;
19796
+ var CARD_MAX_W = 340;
19797
+ var topic_colors = [
19798
+ "rgb(237, 201, 73)",
19799
+ "rgb(118, 183, 178)",
19800
+ "rgb(255, 157, 167)",
19801
+ "rgb(175, 122, 161)",
19802
+ "rgb(89, 161, 79)",
19803
+ "rgb(186, 176, 171)",
19804
+ "rgb(66, 146, 198)"
19805
+ ];
19806
+ var SYSTEM_TOPIC_COLOR = "rgb(148, 163, 184)";
19771
19807
  /***************************************************************
19772
19808
  * Data
19773
19809
  ***************************************************************/
@@ -19829,48 +19865,254 @@ function build_ui$2(gobj) {
19829
19865
  gobj_write_attr(gobj, "$container", $container);
19830
19866
  }
19831
19867
  /************************************************************
19868
+ * The shape of a hook/fkey field, from the type it declares.
19869
+ * `dict` and `object` are the SAME thing to treedb (both build
19870
+ * a json object keyed by child id), and so are `list` and
19871
+ * `array` — see the hook/fkey switches in tr_treedb.c. A
19872
+ * `string` holds one reference, so it draws as one.
19873
+ ************************************************************/
19874
+ function hook_mark(type) {
19875
+ if (type === "dict" || type === "object") return "{}";
19876
+ if (type === "list" || type === "array") return "[]";
19877
+ return "()";
19878
+ }
19879
+ /************************************************************
19880
+ * The fields of one topic, as the schema declares them.
19881
+ *
19882
+ * The marks are the notation of the schema `.c` literals
19883
+ * (treedb_schema_*.c, treedb_system_schema.c), so the
19884
+ * drawing and the source read the same:
19885
+ * {} dict hook (N unique children)
19886
+ * [] list hook (n not-unique children)
19887
+ * () 1 child
19888
+ * (↖) 1 fkey (1 parent)
19889
+ * [↖] n fkeys (n parents)
19890
+ * {↖} N fkeys (N parents)
19891
+ * * required
19892
+ * # the primary key
19893
+ *
19894
+ * A column can be BOTH hook and fkey, so the flags are read
19895
+ * here rather than through treedb_get_field_desc's single
19896
+ * `type`, which keeps only the last flag it saw.
19897
+ ************************************************************/
19898
+ function schema_rows(desc) {
19899
+ let rows = [];
19900
+ if (!is_object(desc) || !Array.isArray(desc.cols)) return rows;
19901
+ for (let col of desc.cols) {
19902
+ if (!is_object(col) || !col.id) continue;
19903
+ let flags = Array.isArray(col.flag) ? col.flag : [];
19904
+ let is_hook = flags.indexOf("hook") >= 0;
19905
+ let is_fkey = flags.indexOf("fkey") >= 0;
19906
+ let mark = "";
19907
+ if (is_hook) mark = hook_mark(col.type);
19908
+ if (is_fkey) {
19909
+ let fmark = hook_mark(col.type).replace("}", "↖}").replace("]", "↖]").replace(")", "↖)");
19910
+ mark = mark ? mark + " " + fmark : fmark;
19911
+ }
19912
+ rows.push({
19913
+ name: col.id,
19914
+ type: col.type || "",
19915
+ mark,
19916
+ is_hook,
19917
+ is_fkey,
19918
+ is_pkey: col.id === desc.pkey,
19919
+ required: flags.indexOf("required") >= 0 || flags.indexOf("notnull") >= 0
19920
+ });
19921
+ }
19922
+ return rows;
19923
+ }
19924
+ /************************************************************
19925
+ * Size of the card that holds those rows. The width follows
19926
+ * the longest line so a long field name is not clipped into
19927
+ * an ellipsis — the point of the drawing is to read them.
19928
+ ************************************************************/
19929
+ function card_size(rows) {
19930
+ let longest = 0;
19931
+ for (let row of rows) {
19932
+ let len = row.name.length + (row.mark ? row.mark.length + 2 : 0) + 2;
19933
+ if (len > longest) longest = len;
19934
+ }
19935
+ let w = Math.round(26 + longest * 6.6);
19936
+ if (w < CARD_MIN_W) w = CARD_MIN_W;
19937
+ if (w > CARD_MAX_W) w = CARD_MAX_W;
19938
+ let h = 44 + rows.length * CARD_ROW_H;
19939
+ return [w, h];
19940
+ }
19941
+ /************************************************************
19942
+ * Vertical placement of a field's port, as a fraction of the
19943
+ * card height: the centre of its own row.
19944
+ ************************************************************/
19945
+ function row_placement(index, height) {
19946
+ return (37 + index * CARD_ROW_H + CARD_ROW_H / 2) / height;
19947
+ }
19948
+ /************************************************************
19949
+ * The card itself. Header = topic name on its topic colour;
19950
+ * body = one line per field, in schema order.
19951
+ ************************************************************/
19952
+ function build_card_innerHTML(topic, rows, color, dark) {
19953
+ let surface = dark ? "#1b2230" : "#ffffff";
19954
+ let bg = dark ? `color-mix(in srgb, ${color} 18%, #232b38)` : `color-mix(in srgb, ${color} 6%, ${surface})`;
19955
+ let border = dark ? `color-mix(in srgb, ${color} 85%, #ffffff)` : color;
19956
+ let header_bg = dark ? `color-mix(in srgb, ${color} 45%, #2c3542)` : `color-mix(in srgb, ${color} 28%, ${surface})`;
19957
+ let title_color = dark ? "#e8eaed" : "#0f172a";
19958
+ let text_color = dark ? "#d3d8de" : "#334155";
19959
+ let mute_color = dark ? "#98a2b0" : "#7c8694";
19960
+ let rule_color = dark ? "rgba(255,255,255,0.06)" : "rgba(15,23,42,0.05)";
19961
+ 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)";
19962
+ let rows_html = "";
19963
+ for (let row of rows) {
19964
+ let lead = row.is_pkey ? "#" : row.required ? "*" : "";
19965
+ let name_weight = row.is_pkey || row.required ? "600" : "400";
19966
+ let name_color = row.is_hook || row.is_fkey ? title_color : text_color;
19967
+ rows_html += ` <div class="TREEDB_SCHEMA_FIELD" style="
19968
+ display: flex; align-items: center; gap: 6px;
19969
+ height: ${CARD_ROW_H}px; line-height: ${CARD_ROW_H}px;
19970
+ padding: 0 10px; border-top: 1px solid ${rule_color};
19971
+ ">
19972
+ <span style="
19973
+ width: 8px; flex: 0 0 8px; text-align: center;
19974
+ color: ${mute_color}; font-size: 11px;
19975
+ ">${lead}</span>
19976
+ <span style="
19977
+ flex: 1 1 auto; min-width: 0; overflow: hidden;
19978
+ text-overflow: ellipsis; white-space: nowrap;
19979
+ font-size: 12px; font-weight: ${name_weight}; color: ${name_color};
19980
+ ">${escapeHtml(row.name)}</span>
19981
+ <span style="
19982
+ flex: 0 0 auto; font-size: 11px; color: ${mute_color};
19983
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
19984
+ ">${escapeHtml(row.mark)}</span>
19985
+ </div>
19986
+ `;
19987
+ }
19988
+ return `
19989
+ <div class="TREEDB_SCHEMA_CARD" title="${escapeHtml(topic)}" style="
19990
+ box-sizing: border-box;
19991
+ width: 100%;
19992
+ height: 100%;
19993
+ background: ${bg};
19994
+ border: 1.5px solid ${border};
19995
+ border-radius: 8px;
19996
+ box-shadow: ${shadow};
19997
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
19998
+ display: flex;
19999
+ flex-direction: column;
20000
+ overflow: hidden;
20001
+ cursor: pointer;
20002
+ ">
20003
+ <div class="TREEDB_SCHEMA_CARD_HEADER" style="
20004
+ height: ${CARD_HEADER_H}px; line-height: ${CARD_HEADER_H}px;
20005
+ flex: 0 0 ${CARD_HEADER_H}px;
20006
+ padding: 0 10px; background: ${header_bg}; color: ${title_color};
20007
+ font-size: 13px; font-weight: 700;
20008
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
20009
+ ">${escapeHtml(topic)}</div>
20010
+ <div class="TREEDB_SCHEMA_CARD_BODY" style="
20011
+ flex: 1 1 auto; padding: ${CARD_PAD_V}px 0; overflow: hidden;
20012
+ ">
20013
+ ${rows_html} </div>
20014
+ </div>
20015
+ `;
20016
+ }
20017
+ /************************************************************
19832
20018
  * Derive {nodes, edges} from the schema.
19833
- * Node = a topic. Edge = a hook (parent -> child) or an
19834
- * fkey (child -> parent, reversed to parent -> child), deduped.
20019
+ *
20020
+ * Node = a topic, drawn as the card the `.c` literal draws in
20021
+ * ASCII: its name and its fields. Edge = a hook, from the row
20022
+ * that declares it to the fkey row of the child it names —
20023
+ * `'hook': {'users': 'departments'}` says both ends, so the
20024
+ * arrow can land where the `.c` drawing lands it. An fkey
20025
+ * whose parent declares no hook still gets its edge, or a
20026
+ * half-declared schema would draw as disconnected.
20027
+ *
19835
20028
  * Left-to-right dagre follows the parent -> child data flow.
19836
20029
  ************************************************************/
19837
20030
  function schema_to_graph(gobj) {
19838
20031
  let descs = gobj_read_attr(gobj, "descs");
19839
20032
  let system = gobj_read_bool_attr(gobj, "system");
20033
+ let dark = yui_is_dark();
19840
20034
  let nodes = [];
19841
- let topic_set = {};
20035
+ let cards = {};
19842
20036
  if (!is_object(descs)) return {
19843
20037
  nodes,
19844
20038
  edges: []
19845
20039
  };
20040
+ let idx = 0;
19846
20041
  for (let topic of Object.keys(descs)) {
19847
- if (!system && topic.substring(0, 2) === "__") continue;
19848
- topic_set[topic] = true;
20042
+ let is_system = topic.substring(0, 2) === "__";
20043
+ if (!system && is_system) continue;
20044
+ let rows = schema_rows(descs[topic]);
20045
+ let color;
20046
+ if (is_system) color = SYSTEM_TOPIC_COLOR;
20047
+ else {
20048
+ color = topic_colors[idx % topic_colors.length];
20049
+ idx++;
20050
+ }
20051
+ cards[topic] = {
20052
+ rows,
20053
+ size: card_size(rows),
20054
+ color
20055
+ };
20056
+ }
20057
+ for (let topic of Object.keys(cards)) {
20058
+ let card = cards[topic];
20059
+ let [w, h] = card.size;
20060
+ let ports = [];
20061
+ for (let i = 0; i < card.rows.length; i++) {
20062
+ let row = card.rows[i];
20063
+ if (!row.is_hook && !row.is_fkey) continue;
20064
+ ports.push({
20065
+ key: row.name,
20066
+ placement: [row.is_hook ? 1 : 0, row_placement(i, h)],
20067
+ fill: card.color,
20068
+ stroke: getStrokeColor(card.color)
20069
+ });
20070
+ }
19849
20071
  nodes.push({
19850
20072
  id: topic,
19851
- data: { topic_name: topic }
20073
+ type: "html",
20074
+ style: {
20075
+ size: [w, h],
20076
+ dx: -w / 2,
20077
+ dy: -h / 2,
20078
+ innerHTML: build_card_innerHTML(topic, card.rows, card.color, dark),
20079
+ port: ports.length > 0,
20080
+ ports,
20081
+ portR: 3,
20082
+ portLineWidth: 1
20083
+ },
20084
+ data: {
20085
+ topic_name: topic,
20086
+ rows: card.rows,
20087
+ color: card.color
20088
+ }
19852
20089
  });
19853
20090
  }
19854
20091
  let edge_seen = {};
19855
20092
  let edges = [];
19856
- let add_edge = (source, target) => {
19857
- if (!topic_set[source] || !topic_set[target] || source === target) return;
19858
- let key = source + "" + target;
20093
+ let add_edge = (source, source_port, target, target_port) => {
20094
+ if (!cards[source] || !cards[target]) return;
20095
+ let key = `${source}|${source_port}|${target}|${target_port}`;
19859
20096
  if (edge_seen[key]) return;
19860
20097
  edge_seen[key] = true;
19861
20098
  edges.push({
19862
20099
  id: key,
20100
+ type: "cubic",
19863
20101
  source,
19864
- target
20102
+ target,
20103
+ style: {
20104
+ sourcePort: source_port,
20105
+ targetPort: target_port
20106
+ }
19865
20107
  });
19866
20108
  };
19867
- for (let topic of Object.keys(descs)) {
20109
+ for (let topic of Object.keys(cards)) {
19868
20110
  let desc = descs[topic];
19869
20111
  if (!is_object(desc) || !Array.isArray(desc.cols)) continue;
19870
20112
  for (let col of desc.cols) {
19871
- if (!col) continue;
19872
- if (is_object(col.hook)) for (let child of Object.keys(col.hook)) add_edge(topic, child);
19873
- else if (is_object(col.fkey)) for (let parent of Object.keys(col.fkey)) add_edge(parent, topic);
20113
+ if (!is_object(col) || !col.id) continue;
20114
+ if (is_object(col.hook)) for (let child of Object.keys(col.hook)) add_edge(topic, col.id, child, col.hook[child]);
20115
+ if (is_object(col.fkey)) for (let parent of Object.keys(col.fkey)) add_edge(parent, col.fkey[parent], topic, col.id);
19874
20116
  }
19875
20117
  }
19876
20118
  return {
@@ -19879,26 +20121,15 @@ function schema_to_graph(gobj) {
19879
20121
  };
19880
20122
  }
19881
20123
  /************************************************************
19882
- * The theme-dependent styles, in ONE place: they are applied
19883
- * as the graph is built and re-applied on a theme switch
20124
+ * The theme-dependent edge style, in ONE place: applied as
20125
+ * the graph is built and re-applied on a theme switch
19884
20126
  * (ac_theme), which restyles the LIVE graph — rebuilding it
19885
20127
  * would drop the user's zoom/pan and any dragged node.
19886
20128
  ************************************************************/
19887
- function node_style(dark) {
19888
- return {
19889
- size: 40,
19890
- fill: "#5B8FF9",
19891
- labelText: (d) => d.id,
19892
- labelPlacement: "bottom",
19893
- labelFill: dark ? "#e6e6e6" : "#333333",
19894
- labelBackground: true,
19895
- labelBackgroundFill: dark ? "rgba(0,0,0,0.5)" : "rgba(255,255,255,0.7)",
19896
- cursor: "pointer"
19897
- };
19898
- }
19899
20129
  function edge_style(dark) {
19900
20130
  return {
19901
- stroke: dark ? "#666666" : "#bbbbbb",
20131
+ stroke: dark ? "#7a8593" : "#9aa4b2",
20132
+ lineWidth: 1.2,
19902
20133
  endArrow: true
19903
20134
  };
19904
20135
  }
@@ -19930,13 +20161,12 @@ function build_graph$1(gobj) {
19930
20161
  container: $container,
19931
20162
  autoResize: true,
19932
20163
  data,
19933
- node: { style: node_style(dark) },
19934
20164
  edge: { style: edge_style(dark) },
19935
20165
  layout: {
19936
20166
  type: "antv-dagre",
19937
20167
  rankdir: "LR",
19938
- nodesep: 24,
19939
- ranksep: 60
20168
+ nodesep: 28,
20169
+ ranksep: 90
19940
20170
  },
19941
20171
  behaviors: [
19942
20172
  "zoom-canvas",
@@ -20021,8 +20251,17 @@ function ac_theme$1(gobj, event, kw, src) {
20021
20251
  let dark = kw && kw.theme ? kw.theme === "dark" : yui_is_dark();
20022
20252
  try {
20023
20253
  graph.setTheme(dark ? "dark" : "light");
20024
- graph.setNode({ style: node_style(dark) });
20025
20254
  graph.setEdge({ style: edge_style(dark) });
20255
+ let updates = [];
20256
+ for (let node of graph.getNodeData()) {
20257
+ let data = node.data;
20258
+ if (!is_object(data) || !Array.isArray(data.rows)) continue;
20259
+ updates.push({
20260
+ id: node.id,
20261
+ style: { innerHTML: build_card_innerHTML(data.topic_name, data.rows, data.color, dark) }
20262
+ });
20263
+ }
20264
+ if (updates.length > 0) graph.updateNodeData(updates);
20026
20265
  graph.draw().catch((e) => {
20027
20266
  log_error(`${gobj_short_name(gobj)}: schema graph redraw failed: ${e}`);
20028
20267
  });
@@ -20087,6 +20326,58 @@ function register_c_yui_treedb_schema() {
20087
20326
  return create_gclass$2(GCLASS_NAME$2);
20088
20327
  }
20089
20328
  //#endregion
20329
+ //#region src/treedb_node_label.js
20330
+ /***********************************************************************
20331
+ * treedb_node_label.js
20332
+ *
20333
+ * Pure, testable logic behind the label of a node in the treedb
20334
+ * graph: WHAT A RECORD IS CALLED, which is not always what it is
20335
+ * keyed by. Kept out of the gclass so it can be unit-tested with
20336
+ * no DOM and no G6.
20337
+ *
20338
+ * Copyright (c) 2026, ArtGins.
20339
+ * All Rights Reserved.
20340
+ ***********************************************************************/
20341
+ /************************************************************
20342
+ * What a node is CALLED, which is not always what it is
20343
+ * keyed by.
20344
+ *
20345
+ * A topic whose id column is flagged `rowid` or `uuid` keys
20346
+ * its records by a value nobody reads — that is the point of
20347
+ * those flags — and the name a human knows the record by
20348
+ * lives in the secondary key the topic declares (`pkey2s`,
20349
+ * carried in the desc since SDK > 7.13.0). The `topics` and
20350
+ * `cols` topics of treedb_system_schema are the case that
20351
+ * forced this: keyed by rowid, named in `value`, so every
20352
+ * card in the graph read "181", "225", "193".
20353
+ *
20354
+ * The pkey stays reachable: it is the card's tooltip.
20355
+ *
20356
+ * Falls back to the id whenever the schema does not say
20357
+ * otherwise — an older node whose desc carries no `pkey2s`
20358
+ * included.
20359
+ ************************************************************/
20360
+ function node_label(desc, record) {
20361
+ let id = record.id;
20362
+ let id_col = null;
20363
+ if (Array.isArray(desc.cols)) {
20364
+ for (let col of desc.cols) if (col && col.id === (desc.pkey || "id")) {
20365
+ id_col = col;
20366
+ break;
20367
+ }
20368
+ }
20369
+ if (!id_col || !Array.isArray(id_col.flag)) return id;
20370
+ if (id_col.flag.indexOf("rowid") < 0 && id_col.flag.indexOf("uuid") < 0) return id;
20371
+ let pkey2s = desc.pkey2s;
20372
+ if (typeof pkey2s === "string") pkey2s = pkey2s ? [pkey2s] : [];
20373
+ if (!Array.isArray(pkey2s)) return id;
20374
+ for (let name of pkey2s) {
20375
+ let value = record[name];
20376
+ if (typeof value === "string" && value.length > 0) return value;
20377
+ }
20378
+ return id;
20379
+ }
20380
+ //#endregion
20090
20381
  //#region node_modules/@babel/runtime/helpers/esm/typeof.js
20091
20382
  function _typeof(o) {
20092
20383
  "@babel/helpers - typeof";
@@ -47619,19 +47910,19 @@ function create_topic_node(gobj, desc, record) {
47619
47910
  style.size = [116, 40];
47620
47911
  style.dx = -58;
47621
47912
  style.dy = -20;
47622
- style.innerHTML = build_chip_innerHTML(desc.color, priv.theme, record.icon, record.id);
47913
+ style.innerHTML = build_chip_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), record.id);
47623
47914
  } else if (node_treedb_type === "extended") {
47624
47915
  node_graph_type = "html";
47625
47916
  style.size = [144, 66];
47626
47917
  style.dx = -72;
47627
47918
  style.dy = -33;
47628
- style.innerHTML = build_node_innerHTML(desc.color, priv.theme, record.icon, record.id, desc.topic_name, true);
47919
+ style.innerHTML = build_node_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), desc.topic_name, true, record.id);
47629
47920
  } else {
47630
47921
  node_graph_type = "html";
47631
47922
  style.size = [172, 96];
47632
47923
  style.dx = -86;
47633
47924
  style.dy = -48;
47634
- style.innerHTML = build_node_innerHTML(desc.color, priv.theme, record.icon, record.id, desc.topic_name);
47925
+ style.innerHTML = build_node_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), desc.topic_name, false, record.id);
47635
47926
  }
47636
47927
  let topic_props = priv._graph_properties[desc.topic_name];
47637
47928
  let topic_defaults = is_object(topic_props) && is_object(topic_props.defaults) ? topic_props.defaults : null;
@@ -47699,15 +47990,15 @@ function update_topic_node(gobj, desc, node_name, record) {
47699
47990
  nodedata.data.record = record;
47700
47991
  if (desc.node_treedb_type === "child") graph.updateNodeData([{
47701
47992
  id: node_name,
47702
- style: { innerHTML: build_chip_innerHTML(desc.color, priv.theme, record.icon, record.id) }
47993
+ style: { innerHTML: build_chip_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), record.id) }
47703
47994
  }]);
47704
47995
  else if (desc.node_treedb_type === "extended") graph.updateNodeData([{
47705
47996
  id: node_name,
47706
- style: { innerHTML: build_node_innerHTML(desc.color, priv.theme, record.icon, record.id, desc.topic_name, true) }
47997
+ style: { innerHTML: build_node_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), desc.topic_name, true, record.id) }
47707
47998
  }]);
47708
47999
  else if (desc.node_treedb_type === "hierarchical") graph.updateNodeData([{
47709
48000
  id: node_name,
47710
- style: { innerHTML: build_node_innerHTML(desc.color, priv.theme, record.icon, record.id, desc.topic_name) }
48001
+ style: { innerHTML: build_node_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), desc.topic_name, false, record.id) }
47711
48002
  }]);
47712
48003
  } catch (e) {
47713
48004
  log_error(e.message);
@@ -49614,7 +49905,7 @@ function show_node_popover(gobj) {
49614
49905
  };
49615
49906
  if (node_graph_type === "hierarchical") {
49616
49907
  let record = nodeData.data.record || {};
49617
- updateStyle.innerHTML = build_node_innerHTML(fill, priv.theme, record.icon, record.id, nodeData.data.desc.topic_name);
49908
+ updateStyle.innerHTML = build_node_innerHTML(fill, priv.theme, record.icon, node_label(nodeData.data.desc, record), nodeData.data.desc.topic_name, false, record.id);
49618
49909
  }
49619
49910
  graph.updateNodeData([{
49620
49911
  id: node_id,
@@ -49654,7 +49945,7 @@ function show_node_popover(gobj) {
49654
49945
  };
49655
49946
  if (node_graph_type === "hierarchical") {
49656
49947
  let record = nodeData.data.record || {};
49657
- restoreStyle.innerHTML = build_node_innerHTML(origFill, priv.theme, record.icon, record.id, nodeData.data.desc.topic_name);
49948
+ restoreStyle.innerHTML = build_node_innerHTML(origFill, priv.theme, record.icon, node_label(nodeData.data.desc, record), nodeData.data.desc.topic_name, false, record.id);
49658
49949
  }
49659
49950
  graph.updateNodeData([{
49660
49951
  id: node_id,
@@ -49755,15 +50046,15 @@ function refresh_html_nodes_theme(gobj, theme) {
49755
50046
  let record = nd.data.record || {};
49756
50047
  if (tt === "hierarchical") updates.push({
49757
50048
  id: nodes[i].id,
49758
- style: { innerHTML: build_node_innerHTML(nd.data.desc.color, theme, record.icon, record.id, nd.data.desc.topic_name) }
50049
+ 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) }
49759
50050
  });
49760
50051
  else if (tt === "child") updates.push({
49761
50052
  id: nodes[i].id,
49762
- style: { innerHTML: build_chip_innerHTML(nd.data.desc.color, theme, record.icon, record.id) }
50053
+ style: { innerHTML: build_chip_innerHTML(nd.data.desc.color, theme, record.icon, node_label(nd.data.desc, record), record.id) }
49763
50054
  });
49764
50055
  else if (tt === "extended") updates.push({
49765
50056
  id: nodes[i].id,
49766
- style: { innerHTML: build_node_innerHTML(nd.data.desc.color, theme, record.icon, record.id, nd.data.desc.topic_name, true) }
50057
+ 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) }
49767
50058
  });
49768
50059
  }
49769
50060
  if (updates.length > 0) graph.updateNodeData(updates);
@@ -49795,7 +50086,8 @@ function refresh_default_edges_theme(gobj, theme) {
49795
50086
  * but lighter (1px border, no shadow, single line). The name is
49796
50087
  * always legible (ellipsis + native title tooltip on overflow).
49797
50088
  ************************************************************/
49798
- function build_chip_innerHTML(color, theme, icon, id) {
50089
+ function build_chip_innerHTML(color, theme, icon, label, key) {
50090
+ let title = key || label;
49799
50091
  let dark = theme === "dark";
49800
50092
  let bg = dark ? `color-mix(in srgb, ${color} 30%, #2c3542)` : `color-mix(in srgb, ${color} 10%, ${dark ? "#1b2230" : "#ffffff"})`;
49801
50093
  let border = dark ? `color-mix(in srgb, ${color} 85%, #ffffff)` : color;
@@ -49806,7 +50098,7 @@ function build_chip_innerHTML(color, theme, icon, id) {
49806
50098
  margin-right: 6px; flex: 0 0 auto;
49807
50099
  "/>`;
49808
50100
  return `
49809
- <div title="${escapeHtml(id)}" style="
50101
+ <div title="${escapeHtml(title)}" style="
49810
50102
  box-sizing: border-box;
49811
50103
  width: 100%;
49812
50104
  height: 100%;
@@ -49823,7 +50115,7 @@ function build_chip_innerHTML(color, theme, icon, id) {
49823
50115
  ">${icon_html}<span style="
49824
50116
  font-size: 12px; font-weight: 600; line-height: 1;
49825
50117
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
49826
- ">${escapeHtml(id)}</span>
50118
+ ">${escapeHtml(label)}</span>
49827
50119
  </div>
49828
50120
  `;
49829
50121
  }
@@ -49837,7 +50129,8 @@ function build_chip_innerHTML(color, theme, icon, id) {
49837
50129
  * colour is kept (per-topic differentiation) but softened via
49838
50130
  * color-mix instead of a harsh saturated fill. Theme-aware.
49839
50131
  ************************************************************/
49840
- function build_node_innerHTML(color, theme, icon, id, topic_name, structural) {
50132
+ function build_node_innerHTML(color, theme, icon, label, topic_name, structural, key) {
50133
+ let title = key || label;
49841
50134
  let dark = theme === "dark";
49842
50135
  let surface = dark ? "#1b2230" : "#ffffff";
49843
50136
  let bg, border, border_style;
@@ -49867,7 +50160,7 @@ function build_node_innerHTML(color, theme, icon, id, topic_name, structural) {
49867
50160
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
49868
50161
  ">${escapeHtml(topic_name)}</div>`;
49869
50162
  return `
49870
- <div title="${escapeHtml(id)}" style="
50163
+ <div title="${escapeHtml(title)}" style="
49871
50164
  box-sizing: border-box;
49872
50165
  width: 100%;
49873
50166
  height: 100%;
@@ -49890,7 +50183,7 @@ function build_node_innerHTML(color, theme, icon, id, topic_name, structural) {
49890
50183
  max-width: 100%; overflow: hidden; text-overflow: ellipsis;
49891
50184
  display: -webkit-box; -webkit-line-clamp: 2;
49892
50185
  -webkit-box-orient: vertical; word-break: break-word;
49893
- ">${escapeHtml(id)}</div>${sub_html}
50186
+ ">${escapeHtml(label)}</div>${sub_html}
49894
50187
  </div>
49895
50188
  `;
49896
50189
  }
@@ -50111,7 +50404,7 @@ function apply_node_properties(gobj, node_id, fill, stroke, lineWidth, scope) {
50111
50404
  };
50112
50405
  if (nd.data.desc.node_treedb_type === "hierarchical") {
50113
50406
  let record = nd.data.record || {};
50114
- updateStyle.innerHTML = build_node_innerHTML(fill, priv.theme, record.icon, record.id, nd.data.desc.topic_name);
50407
+ updateStyle.innerHTML = build_node_innerHTML(fill, priv.theme, record.icon, node_label(nd.data.desc, record), nd.data.desc.topic_name, false, record.id);
50115
50408
  }
50116
50409
  updates.push({
50117
50410
  id: nodes[i].id,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "5.16.0",
3
+ "version": "5.17.0",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",