@yuneta/gobj-ui 7.14.3 → 7.16.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.
@@ -53689,11 +53689,22 @@ function inject_svg_icons() {
53689
53689
  ***********************************************************************/
53690
53690
  /***************************************************************
53691
53691
  * YuiToolbar — G6 Toolbar subclass that adds per-item className
53692
- * and disabled support.
53692
+ * and disabled support, plus three item kinds G6 does not have.
53693
53693
  *
53694
53694
  * Each item in getItems() may carry:
53695
53695
  * className — CSS class added to the div (e.g. 'EV_SAVE_GRAPH')
53696
53696
  * disabled — boolean; sets the 'disabled' attribute initially
53697
+ * text — render this text instead of a sprite symbol; a
53698
+ * label is the only readable way to say `1:1`, and
53699
+ * every editor that offers actual-size writes it
53700
+ * readout — a text item that REPORTS instead of acting (the
53701
+ * zoom level); it is not a button
53702
+ * separator — a group divider, not an item
53703
+ *
53704
+ * The base class fires onClick only for elements whose class list
53705
+ * contains `g6-toolbar-item`, so a separator and a readout carry
53706
+ * their own class and are inert by construction, with no guard in
53707
+ * the click handler.
53697
53708
  *
53698
53709
  * With className set to the event name, the lib_graph.js state
53699
53710
  * functions (set_submit_state, disableElements, …) work on toolbar
@@ -53703,9 +53714,15 @@ function inject_svg_icons() {
53703
53714
  var YuiToolbar = class extends Toolbar {
53704
53715
  async getDOMContent() {
53705
53716
  return (await this.options.getItems()).map((item) => {
53717
+ if (item.separator) return `<div class="g6-toolbar-sep" aria-hidden="true"></div>`;
53706
53718
  const extra_class = item.className ? ` ${item.className}` : "";
53719
+ const title = item.title ?? "";
53720
+ if (item.readout) return `<div class="g6-toolbar-readout${extra_class}" title="${title}" aria-label="${title}">${item.text ?? ""}</div>`;
53707
53721
  const disabled = item.disabled ? " disabled" : "";
53708
- return `<div class="g6-toolbar-item${extra_class}" value="${item.value}" title="${item.title ?? ""}"${disabled}><svg aria-hidden="true" focusable="false"><use xlink:href="#${item.id}"></use></svg></div>`;
53722
+ const is_text = item.text !== void 0;
53723
+ const kind_class = is_text ? " g6-toolbar-item-text" : "";
53724
+ const body = is_text ? `<span class="g6-toolbar-text">${item.text}</span>` : `<svg aria-hidden="true" focusable="false"><use xlink:href="#${item.id}"></use></svg>`;
53725
+ return `<div class="g6-toolbar-item${kind_class}${extra_class}" value="${item.value}" title="${title}" aria-label="${title}"${disabled}>${body}</div>`;
53709
53726
  }).join("");
53710
53727
  }
53711
53728
  };
@@ -53717,6 +53734,7 @@ ensure_drag_canvas_patch();
53717
53734
  var GCLASS_NAME$1 = "C_G6_NODES_TREE";
53718
53735
  var HIGHLIGHT_COLOR = "#f0a020";
53719
53736
  var HIGHLIGHT_HALO = "rgba(240,160,32,0.35)";
53737
+ var SELECT_RING = "rgba(59,130,246,0.95)";
53720
53738
  /***************************************************************
53721
53739
  * Internal layout and operation mode definitions
53722
53740
  ***************************************************************/
@@ -53828,6 +53846,7 @@ var PRIVATE_DATA$1 = {
53828
53846
  _link_saved_styles: [],
53829
53847
  _focus_topic: null,
53830
53848
  _focus_ids: [],
53849
+ _selected_paint_ids: [],
53831
53850
  _pending_focus_topic: null,
53832
53851
  _pending_find: null,
53833
53852
  _layout_asked: "",
@@ -54050,6 +54069,7 @@ function configure_events(gobj) {
54050
54069
  update_edge_icon_position(gobj);
54051
54070
  update_node_icon_position(gobj);
54052
54071
  update_link_icon_position(gobj);
54072
+ update_zoom_readout(gobj);
54053
54073
  });
54054
54074
  priv._on_language_changed = () => {
54055
54075
  update_toolbar(gobj);
@@ -54115,6 +54135,59 @@ function update_toolbar(gobj) {
54115
54135
  configure_toolbar_edit(gobj);
54116
54136
  if (graph_get_plugin(gobj, "toolbar-edit")) graph.updatePlugin({ key: "toolbar-edit" });
54117
54137
  }
54138
+ /************************************************************
54139
+ * The floating toolbars follow the theme.
54140
+ *
54141
+ * They used to be pinned to a light background in BOTH themes,
54142
+ * with the icon colour pinned dark so it survived that -- two
54143
+ * light islands sitting over a dark canvas. The tokens do the
54144
+ * flipping now; the fallbacks are the old forced-light values, so
54145
+ * a host without Bulma gets exactly what it had.
54146
+ ************************************************************/
54147
+ function toolbar_style(extra) {
54148
+ return Object.assign({
54149
+ backgroundColor: "var(--bulma-scheme-main, #f5f5f5)",
54150
+ color: "var(--bulma-text-strong, #333)",
54151
+ padding: "8px",
54152
+ boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)",
54153
+ borderRadius: "8px",
54154
+ border: "1px solid var(--bulma-border-weak, #e8e8e8)",
54155
+ opacity: "0.85"
54156
+ }, extra || {});
54157
+ }
54158
+ /************************************************************
54159
+ * The zoom level as a percentage, the way every editor that
54160
+ * shows one writes it. Empty while the graph cannot be asked --
54161
+ * the toolbar is built before the first draw, and a viewport
54162
+ * that does not exist yet has no zoom to report.
54163
+ ************************************************************/
54164
+ function zoom_percent_text(gobj) {
54165
+ let graph = gobj.priv.graph;
54166
+ if (!graph || typeof graph.getZoom !== "function") return "";
54167
+ let zoom;
54168
+ try {
54169
+ zoom = graph.getZoom();
54170
+ } catch (e) {
54171
+ return "";
54172
+ }
54173
+ if (!zoom) return "";
54174
+ return `${Math.round(zoom * 100)}%`;
54175
+ }
54176
+ /************************************************************
54177
+ * Repaint the zoom readout in place.
54178
+ *
54179
+ * The text node is patched instead of re-rendering the plugin:
54180
+ * the readout follows the wheel, and updatePlugin() rebuilds the
54181
+ * whole toolbar's innerHTML -- which would also drop the disabled
54182
+ * state of the edit buttons on every notch of the wheel.
54183
+ ************************************************************/
54184
+ function update_zoom_readout(gobj) {
54185
+ let $container = gobj_read_attr(gobj, "$container");
54186
+ if (!$container) return;
54187
+ let $readout = $container.querySelector(".G6_ZOOM_LEVEL");
54188
+ if (!$readout) return;
54189
+ $readout.textContent = zoom_percent_text(gobj);
54190
+ }
54118
54191
  function configure_toolbar(gobj) {
54119
54192
  let priv = gobj.priv;
54120
54193
  let toolbar_position = gobj_read_str_attr(gobj, "toolbar_position") || "top-left";
@@ -54123,17 +54196,10 @@ function configure_toolbar(gobj) {
54123
54196
  type: "yui-toolbar",
54124
54197
  className: "g6-toolbar-large",
54125
54198
  position: toolbar_position,
54126
- style: {
54127
- backgroundColor: "#f5f5f5",
54128
- color: "#333",
54129
- padding: "8px",
54130
- boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)",
54131
- borderRadius: "8px",
54132
- border: "1px solid #e8e8e8",
54133
- opacity: "0.85",
54199
+ style: toolbar_style({
54134
54200
  marginTop: "12px",
54135
54201
  marginLeft: "12px"
54136
- },
54202
+ }),
54137
54203
  getItems: () => {
54138
54204
  let items = [
54139
54205
  {
@@ -54148,6 +54214,13 @@ function configure_toolbar(gobj) {
54148
54214
  className: "EV_ZOOM_OUT",
54149
54215
  title: t("zoom out")
54150
54216
  },
54217
+ {
54218
+ readout: true,
54219
+ className: "G6_ZOOM_LEVEL",
54220
+ text: zoom_percent_text(gobj),
54221
+ title: t("zoom level")
54222
+ },
54223
+ { separator: true },
54151
54224
  {
54152
54225
  id: "g6-icon-fit",
54153
54226
  value: "auto-fit",
@@ -54155,13 +54228,14 @@ function configure_toolbar(gobj) {
54155
54228
  title: t("auto fit")
54156
54229
  },
54157
54230
  {
54158
- id: "g6-icon-home",
54231
+ text: "1:1",
54159
54232
  value: "reset",
54160
54233
  className: "EV_ZOOM_RESET",
54161
- title: t("reset zoom")
54234
+ title: t("actual size")
54162
54235
  }
54163
54236
  ];
54164
54237
  if (gobj_read_bool_attr(gobj, "with_fullscreen")) {
54238
+ items.push({ separator: true });
54165
54239
  if (priv.is_fullscreen) items.push({
54166
54240
  id: "g6-icon-fullscreen-exit",
54167
54241
  value: "exit-fullscreen",
@@ -54217,15 +54291,7 @@ function configure_toolbar_edit(gobj) {
54217
54291
  type: "yui-toolbar",
54218
54292
  className: "g6-toolbar-large",
54219
54293
  position: "left-top",
54220
- style: {
54221
- backgroundColor: "#f5f5f5",
54222
- color: "#333",
54223
- padding: "8px",
54224
- boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)",
54225
- borderRadius: "8px",
54226
- border: "1px solid #e8e8e8",
54227
- opacity: "0.85"
54228
- },
54294
+ style: toolbar_style(),
54229
54295
  getItems: () => {
54230
54296
  return [
54231
54297
  {
@@ -54301,9 +54367,24 @@ function configure_behaviour(gobj) {
54301
54367
  case "edition":
54302
54368
  priv.edit_mode = true;
54303
54369
  behaviors = [
54304
- "drag-canvas",
54370
+ {
54371
+ type: "drag-canvas",
54372
+ key: "drag-canvas",
54373
+ enable: (event) => !event.shiftKey
54374
+ },
54305
54375
  "zoom-canvas",
54306
- "drag-element"
54376
+ "drag-element",
54377
+ {
54378
+ type: "brush-select",
54379
+ key: "brush-select",
54380
+ trigger: ["shift"],
54381
+ enableElements: ["node"],
54382
+ immediately: false,
54383
+ onSelect: (states) => {
54384
+ let ids = Object.keys(states || {}).filter((id) => (states[id] || []).includes("selected"));
54385
+ gobj_send_event(gobj, "EV_BRUSH_SELECT", { ids }, gobj);
54386
+ }
54387
+ }
54307
54388
  ];
54308
54389
  break;
54309
54390
  case "operation":
@@ -55418,6 +55499,81 @@ function perform_history_op(gobj, is_redo) {
55418
55499
  sync_history_to_backend(gobj, cmd ? cmd.original : null);
55419
55500
  }
55420
55501
  }
55502
+ /************************************************************
55503
+ * The selection.
55504
+ *
55505
+ * G6's `selected` element state IS the selection: `drag-element`
55506
+ * reads it (`getElementDataByState`) to decide what a drag moves,
55507
+ * so keeping the set anywhere else would be a second truth the
55508
+ * drag does not consult. What this gclass keeps is what is
55509
+ * PAINTED -- an html node draws no state style at all (its key
55510
+ * shape is a DOM element), so the ring lives in the card's own
55511
+ * html, exactly like the find highlight, and the painted set
55512
+ * exists to diff the repaint.
55513
+ ************************************************************/
55514
+ function selected_node_ids(gobj) {
55515
+ let graph = gobj.priv.graph;
55516
+ if (!graph) return [];
55517
+ let data;
55518
+ try {
55519
+ data = graph.getElementDataByState("node", "selected") || [];
55520
+ } catch (e) {
55521
+ return [];
55522
+ }
55523
+ return data.map((nd) => nd.id);
55524
+ }
55525
+ /************************************************************
55526
+ * Move the ring to these nodes and off the ones that had it.
55527
+ ************************************************************/
55528
+ function paint_selection(gobj, ids) {
55529
+ let priv = gobj.priv;
55530
+ let prev = priv._selected_paint_ids || [];
55531
+ let next = ids || [];
55532
+ priv._selected_paint_ids = next;
55533
+ repaint_cards(gobj, /* @__PURE__ */ new Set([...prev, ...next]));
55534
+ }
55535
+ /************************************************************
55536
+ * Select a SET of nodes: what a marquee and a shift-click do.
55537
+ *
55538
+ * It leaves `_selected_node_id` null even for a set of one,
55539
+ * because that field is not "the selection", it is "the node
55540
+ * opened for editing" -- the resize handles, the ports and the
55541
+ * popovers hang off it, and none of them means anything over a
55542
+ * set. Clicking a node is what opens one (`select_node`); a
55543
+ * marquee selects, it does not open.
55544
+ ************************************************************/
55545
+ function set_selection(gobj, ids) {
55546
+ let graph = gobj.priv.graph;
55547
+ let next = [];
55548
+ for (let id of ids || []) try {
55549
+ if (graph.getNodeData(id)) next.push(id);
55550
+ } catch (e) {}
55551
+ deselect_node(gobj);
55552
+ if (!next.length) return;
55553
+ history_pause(gobj);
55554
+ try {
55555
+ let states = {};
55556
+ for (let id of next) states[id] = ["selected"];
55557
+ graph.setElementState(states);
55558
+ } catch (e) {
55559
+ log_error(`${gobj_short_name(gobj)}: cannot set the selection: ${e}`);
55560
+ }
55561
+ paint_selection(gobj, next);
55562
+ graph_draw(gobj).then(() => {
55563
+ history_resume(gobj);
55564
+ });
55565
+ }
55566
+ /************************************************************
55567
+ * Add a node to the selection, or take it out of it.
55568
+ ************************************************************/
55569
+ function toggle_in_selection(gobj, node_id) {
55570
+ let priv = gobj.priv;
55571
+ let current = new Set(selected_node_ids(gobj));
55572
+ for (let id of priv._selected_paint_ids || []) current.add(id);
55573
+ if (current.has(node_id)) current.delete(node_id);
55574
+ else current.add(node_id);
55575
+ set_selection(gobj, [...current]);
55576
+ }
55421
55577
  function select_node(gobj, node_id) {
55422
55578
  let priv = gobj.priv;
55423
55579
  let graph = priv.graph;
@@ -55427,6 +55583,7 @@ function select_node(gobj, node_id) {
55427
55583
  graph.setElementState(node_id, ["selected"]);
55428
55584
  } catch (e) {}
55429
55585
  priv._selected_node_id = node_id;
55586
+ paint_selection(gobj, [node_id]);
55430
55587
  show_resize_handles(gobj);
55431
55588
  show_node_icon(gobj);
55432
55589
  graph_draw(gobj).then(() => {
@@ -55442,12 +55599,17 @@ function deselect_node(gobj) {
55442
55599
  hide_node_popover(gobj);
55443
55600
  hide_delete_confirm(gobj);
55444
55601
  hide_unlink_confirm(gobj);
55445
- if (priv._selected_node_id) {
55602
+ let clearing = /* @__PURE__ */ new Set([...selected_node_ids(gobj), ...priv._selected_paint_ids || []]);
55603
+ if (priv._selected_node_id) clearing.add(priv._selected_node_id);
55604
+ if (clearing.size) {
55446
55605
  history_pause(gobj);
55447
55606
  try {
55448
- graph.setElementState(priv._selected_node_id, []);
55607
+ let states = {};
55608
+ for (let id of clearing) states[id] = [];
55609
+ graph.setElementState(states);
55449
55610
  } catch (e) {}
55450
55611
  priv._selected_node_id = null;
55612
+ paint_selection(gobj, []);
55451
55613
  graph_draw(gobj).then(() => {
55452
55614
  history_resume(gobj);
55453
55615
  });
@@ -56734,33 +56896,36 @@ function refresh_minimap(gobj) {
56734
56896
  * same three-way choice — it lived inline in the theme refresh and is
56735
56897
  * shared now. Returns null for a node that carries no desc.
56736
56898
  ************************************************************/
56737
- function node_innerHTML_of(nd, theme, highlight) {
56899
+ function node_innerHTML_of(nd, theme, highlight, selected) {
56738
56900
  if (!nd || !nd.data || !nd.data.desc) return null;
56739
56901
  let desc = nd.data.desc;
56740
56902
  let record = nd.data.record || {};
56741
56903
  let label = node_label(desc, record);
56742
56904
  switch (desc.node_treedb_type) {
56743
- case "child": return build_chip_innerHTML(desc.color, theme, record.icon, label, record.id, highlight);
56744
- case "extended": return build_node_innerHTML(desc.color, theme, record.icon, label, desc.topic_name, true, record.id, highlight);
56745
- case "hierarchical": return build_node_innerHTML(desc.color, theme, record.icon, label, desc.topic_name, false, record.id, highlight);
56905
+ case "child": return build_chip_innerHTML(desc.color, theme, record.icon, label, record.id, highlight, selected);
56906
+ case "extended": return build_node_innerHTML(desc.color, theme, record.icon, label, desc.topic_name, true, record.id, highlight, selected);
56907
+ case "hierarchical": return build_node_innerHTML(desc.color, theme, record.icon, label, desc.topic_name, false, record.id, highlight, selected);
56746
56908
  }
56747
56909
  return null;
56748
56910
  }
56749
56911
  /************************************************************
56750
- * Repaint the cards whose highlight state CHANGES: the ones that had it
56751
- * and lose it, plus the ones that gain it. Only those — a treedb graph
56752
- * is redrawn per keystroke of the find box otherwise.
56912
+ * Repaint these cards with the flags they carry RIGHT NOW.
56913
+ *
56914
+ * One place, because the flags are independent and each used to
56915
+ * be written by whoever repainted last: a find that repainted its
56916
+ * matches erased the selection ring off them, and a selection
56917
+ * repainted over a match erased the amber. Both are read here
56918
+ * from where they live.
56753
56919
  ************************************************************/
56754
- function apply_node_highlight(gobj, prev_ids, next_ids) {
56920
+ function repaint_cards(gobj, ids) {
56755
56921
  let priv = gobj.priv;
56756
56922
  let graph = priv.graph;
56757
- if (!graph) return;
56758
- let next = new Set(next_ids || []);
56759
- let touched = /* @__PURE__ */ new Set([...prev_ids || [], ...next]);
56760
- if (touched.size === 0) return;
56923
+ if (!graph || !ids || !ids.size) return;
56924
+ let focus = new Set(priv._focus_ids || []);
56925
+ let selected = new Set(priv._selected_paint_ids || []);
56761
56926
  let updates = [];
56762
- for (let id of touched) {
56763
- let html = node_innerHTML_of(graph.getNodeData(id), priv.theme, next.has(id));
56927
+ for (let id of ids) {
56928
+ let html = node_innerHTML_of(graph.getNodeData(id), priv.theme, focus.has(id), selected.has(id));
56764
56929
  if (html !== null) updates.push({
56765
56930
  id,
56766
56931
  style: { innerHTML: html }
@@ -56771,19 +56936,32 @@ function apply_node_highlight(gobj, prev_ids, next_ids) {
56771
56936
  graph.updateNodeData(updates);
56772
56937
  graph.draw();
56773
56938
  } catch (e) {
56774
- log_error(`${gobj_short_name(gobj)}: cannot repaint the highlight: ${e}`);
56939
+ log_error(`${gobj_short_name(gobj)}: cannot repaint the cards: ${e}`);
56775
56940
  }
56776
56941
  }
56942
+ /************************************************************
56943
+ * Repaint the cards whose highlight state CHANGES: the ones that had it
56944
+ * and lose it, plus the ones that gain it. Only those — a treedb graph
56945
+ * is redrawn per keystroke of the find box otherwise.
56946
+ ************************************************************/
56947
+ function apply_node_highlight(gobj, prev_ids, next_ids) {
56948
+ if (!gobj.priv.graph) return;
56949
+ let next = new Set(next_ids || []);
56950
+ let touched = /* @__PURE__ */ new Set([...prev_ids || [], ...next]);
56951
+ if (touched.size === 0) return;
56952
+ repaint_cards(gobj, touched);
56953
+ }
56777
56954
  function refresh_html_nodes_theme(gobj, theme) {
56778
56955
  let priv = gobj.priv;
56779
56956
  let graph = priv.graph;
56780
56957
  if (!graph) return;
56781
56958
  let nodes = graph.getData().nodes || [];
56782
56959
  let highlighted = new Set(priv._focus_ids || []);
56960
+ let selected = new Set(priv._selected_paint_ids || []);
56783
56961
  let updates = [];
56784
56962
  for (let i = 0; i < nodes.length; i++) {
56785
56963
  let id = nodes[i].id;
56786
- let html = node_innerHTML_of(graph.getNodeData(id), theme, highlighted.has(id));
56964
+ let html = node_innerHTML_of(graph.getNodeData(id), theme, highlighted.has(id), selected.has(id));
56787
56965
  if (html !== null) updates.push({
56788
56966
  id,
56789
56967
  style: { innerHTML: html }
@@ -56813,12 +56991,29 @@ function refresh_default_edges_theme(gobj, theme) {
56813
56991
  if (updates.length > 0) graph.updateEdgeData(updates);
56814
56992
  }
56815
56993
  /************************************************************
56994
+ * The rings a card can wear, composed into one `box-shadow`.
56995
+ *
56996
+ * A node can be a find match and be selected at the same time, so
56997
+ * neither ring may be written by overwriting the other: the amber
56998
+ * halo hugs the card and the blue selection ring is drawn outside
56999
+ * it, which is also the order that reads correctly when only one
57000
+ * of them is on.
57001
+ ************************************************************/
57002
+ function ring_shadow(highlight, selected, base_shadow) {
57003
+ let rings = [];
57004
+ if (highlight) rings.push(`0 0 0 4px ${HIGHLIGHT_HALO}`);
57005
+ if (selected) rings.push(`0 0 0 ${highlight ? "7px" : "3px"} ${SELECT_RING}`);
57006
+ if (base_shadow) rings.push(base_shadow);
57007
+ if (!rings.length) return "";
57008
+ return `box-shadow: ${rings.join(", ")};`;
57009
+ }
57010
+ /************************************************************
56816
57011
  * Build innerHTML for pure-child (leaf) nodes: a compact
56817
57012
  * chip-card. Same colour/typography family as the entity card
56818
57013
  * but lighter (1px border, no shadow, single line). The name is
56819
57014
  * always legible (ellipsis + native title tooltip on overflow).
56820
57015
  ************************************************************/
56821
- function build_chip_innerHTML(color, theme, icon, label, key, highlight) {
57016
+ function build_chip_innerHTML(color, theme, icon, label, key, highlight, selected) {
56822
57017
  let title = key || label;
56823
57018
  let dark = theme === "dark";
56824
57019
  let bg = dark ? `color-mix(in srgb, ${color} 30%, #2c3542)` : `color-mix(in srgb, ${color} 10%, ${dark ? "#1b2230" : "#ffffff"})`;
@@ -56837,7 +57032,7 @@ function build_chip_innerHTML(color, theme, icon, label, key, highlight) {
56837
57032
  height: 100%;
56838
57033
  background: ${bg};
56839
57034
  border: ${highlight ? "3px" : "1px"} solid ${border};
56840
- ${highlight ? `box-shadow: 0 0 0 4px ${HIGHLIGHT_HALO};` : ""}
57035
+ ${ring_shadow(highlight, selected, "")}
56841
57036
  border-radius: 8px;
56842
57037
  color: ${text_color};
56843
57038
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
@@ -56863,7 +57058,7 @@ function build_chip_innerHTML(color, theme, icon, label, key, highlight) {
56863
57058
  * colour is kept (per-topic differentiation) but softened via
56864
57059
  * color-mix instead of a harsh saturated fill. Theme-aware.
56865
57060
  ************************************************************/
56866
- function build_node_innerHTML(color, theme, icon, label, topic_name, structural, key, highlight) {
57061
+ function build_node_innerHTML(color, theme, icon, label, topic_name, structural, key, highlight, selected) {
56867
57062
  let title = key || label;
56868
57063
  let dark = theme === "dark";
56869
57064
  let surface = dark ? "#1b2230" : "#ffffff";
@@ -56905,7 +57100,7 @@ function build_node_innerHTML(color, theme, icon, label, topic_name, structural,
56905
57100
  background: ${bg};
56906
57101
  border: ${highlight ? "3px" : "1.5px"} ${border_style} ${border};
56907
57102
  border-radius: 10px;
56908
- box-shadow: ${highlight ? `0 0 0 4px ${HIGHLIGHT_HALO}, ${shadow}` : shadow};
57103
+ ${ring_shadow(highlight, selected, shadow)}
56909
57104
  color: ${title_color};
56910
57105
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
56911
57106
  display: flex;
@@ -57826,6 +58021,17 @@ function ac_node_drag_end(gobj, event, kw, src) {
57826
58021
  return 0;
57827
58022
  }
57828
58023
  /************************************************************
58024
+ * The rubber band let go: these are the nodes it enclosed.
58025
+ *
58026
+ * They arrive in the kw because `onSelect` runs BEFORE G6 writes
58027
+ * the state, so asking the graph here would answer the previous
58028
+ * selection.
58029
+ ************************************************************/
58030
+ function ac_brush_select(gobj, event, kw, src) {
58031
+ set_selection(gobj, kw && kw.ids || []);
58032
+ return 0;
58033
+ }
58034
+ /************************************************************
57829
58035
  * Node click - publish vertex clicked event
57830
58036
  ************************************************************/
57831
58037
  function ac_node_click(gobj, event, kw, src) {
@@ -57840,7 +58046,8 @@ function ac_node_click(gobj, event, kw, src) {
57840
58046
  topic_name: nodedata.data.desc.topic_name,
57841
58047
  record: nodedata.data.record
57842
58048
  });
57843
- if (priv.edit_mode) {
58049
+ if (priv.edit_mode && kw.evt.shiftKey) toggle_in_selection(gobj, node_id);
58050
+ else if (priv.edit_mode) {
57844
58051
  let containerRect = priv.$container.getBoundingClientRect();
57845
58052
  let canvasPoint = graph.getCanvasByViewport([kw.evt.client.x - containerRect.left, kw.evt.client.y - containerRect.top]);
57846
58053
  let port_key = detect_port_click(gobj, node_id, canvasPoint[0], canvasPoint[1]);
@@ -58067,6 +58274,11 @@ function create_gclass$1(gclass_name) {
58067
58274
  ac_node_drag_end,
58068
58275
  null
58069
58276
  ],
58277
+ [
58278
+ "EV_BRUSH_SELECT",
58279
+ ac_brush_select,
58280
+ null
58281
+ ],
58070
58282
  [
58071
58283
  "EV_ZOOM_IN",
58072
58284
  ac_zoom_in,
@@ -58175,6 +58387,7 @@ function create_gclass$1(gclass_name) {
58175
58387
  ["EV_NODE_CONTEXT_MENU", 0],
58176
58388
  ["EV_CANVAS_CLICK", 0],
58177
58389
  ["EV_NODE_DRAG_END", 0],
58390
+ ["EV_BRUSH_SELECT", 0],
58178
58391
  ["EV_ZOOM_IN", 0],
58179
58392
  ["EV_ZOOM_OUT", 0],
58180
58393
  ["EV_ZOOM_RESET", 0],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.14.3",
3
+ "version": "7.16.0",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",