@yuneta/gobj-ui 7.23.52 → 7.23.53

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.
@@ -6811,6 +6811,7 @@ function build_form_field_conf(gobj, field_desc) {
6811
6811
  field_conf.options = get_fkey_select_options(gobj, field_desc);
6812
6812
  break;
6813
6813
  case "image":
6814
+ case "icon":
6814
6815
  case "string":
6815
6816
  field_conf.tag = "input";
6816
6817
  field_conf.inputType = "text";
@@ -7728,6 +7729,7 @@ function template2columns(gobj, columns, template, sub_elements) {
7728
7729
  case "hook": break;
7729
7730
  case "fkey": break;
7730
7731
  case "image":
7732
+ case "icon":
7731
7733
  case "string":
7732
7734
  column.editor = "input";
7733
7735
  column.editorParams = {
@@ -8166,6 +8168,7 @@ function treedb_value_2_form_value(gobj, field_desc, value) {
8166
8168
  case "date":
8167
8169
  case "color":
8168
8170
  case "image":
8171
+ case "icon":
8169
8172
  case "tel":
8170
8173
  case "template":
8171
8174
  case "table":
@@ -8258,6 +8261,7 @@ function form_value_2_treedb_value(gobj, field_desc, value) {
8258
8261
  case "date":
8259
8262
  case "color":
8260
8263
  case "image":
8264
+ case "icon":
8261
8265
  case "tel": break;
8262
8266
  case "template":
8263
8267
  if ((0, _yuneta_gobj_js.is_string)(value)) try {
@@ -22658,6 +22662,182 @@ function yui_table_filter_clear(table) {
22658
22662
  });
22659
22663
  }
22660
22664
  //#endregion
22665
+ //#region src/lib_icons.js
22666
+ /*********************************************************
22667
+ * lib_icons.js
22668
+ *
22669
+ * Two icon systems are managed here:
22670
+ *
22671
+ * 1. FA-style CSS icons (yui_icons.css)
22672
+ * Usage: <i class="yi-save"></i>
22673
+ * Color: inherits currentColor from parent via CSS mask.
22674
+ *
22675
+ * 2. SVG symbol icons for G6 toolbar (and any other component
22676
+ * that uses <use xlink:href="#id">).
22677
+ * Symbols are injected once into the DOM.
22678
+ * All symbol ids are prefixed with "g6-icon-" to avoid
22679
+ * conflicts with other DOM elements.
22680
+ * Icon paths come from:
22681
+ * fontawesome-free-7.1.0-web/sprites/solid.svg
22682
+ *
22683
+ * G6 toolbar items are managed via CSS class names (className
22684
+ * field in getItems()) using YuiToolbar in c_g6_nodes_tree.js.
22685
+ * This lets lib_graph.js state functions (set_submit_state,
22686
+ * disableElements, …) work on toolbar icons exactly like on
22687
+ * regular Bulma/FA buttons — no icon-specific helpers needed.
22688
+ *
22689
+ * Copyright (c) 2025-2026, ArtGins.
22690
+ * All Rights Reserved.
22691
+ *********************************************************/
22692
+ var CUSTOM_SVG_ICONS_ID = "g6-custom-svgicons";
22693
+ var ICONS = `<svg xmlns="http://www.w3.org/2000/svg">
22694
+ <!-- magnifying-glass-plus -->
22695
+ <symbol id="g6-icon-zoom-in" viewBox="0 0 512 512">
22696
+ <path fill="currentColor" d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376C296.3 401.1 253.9 416 208 416 93.1 416 0 322.9 0 208S93.1 0 208 0 416 93.1 416 208zM208 112c-13.3 0-24 10.7-24 24l0 48-48 0c-13.3 0-24 10.7-24 24s10.7 24 24 24l48 0 0 48c0 13.3 10.7 24 24 24s24-10.7 24-24l0-48 48 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-48 0 0-48c0-13.3-10.7-24-24-24z"/>
22697
+ </symbol>
22698
+ <!-- magnifying-glass-minus -->
22699
+ <symbol id="g6-icon-zoom-out" viewBox="0 0 512 512">
22700
+ <path fill="currentColor" d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376C296.3 401.1 253.9 416 208 416 93.1 416 0 322.9 0 208S93.1 0 208 0 416 93.1 416 208zM136 184c-13.3 0-24 10.7-24 24s10.7 24 24 24l144 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-144 0z"/>
22701
+ </symbol>
22702
+ <!-- house (reset zoom: back to original 100% view) -->
22703
+ <symbol id="g6-icon-home" viewBox="0 0 512 512">
22704
+ <path fill="currentColor" d="M277.8 8.6c-12.3-11.4-31.3-11.4-43.5 0l-224 208c-9.6 9-12.8 22.9-8 35.1S18.8 272 32 272l16 0 0 176c0 35.3 28.7 64 64 64l288 0c35.3 0 64-28.7 64-64l0-176 16 0c13.2 0 25-8.1 29.8-20.3s1.6-26.2-8-35.1l-224-208zM240 320l32 0c26.5 0 48 21.5 48 48l0 96-128 0 0-96c0-26.5 21.5-48 48-48z"/>
22705
+ </symbol>
22706
+ <!-- expand (zoom to fit) -->
22707
+ <symbol id="g6-icon-fit" viewBox="0 0 448 512">
22708
+ <path fill="currentColor" d="M32 32C14.3 32 0 46.3 0 64l0 96c0 17.7 14.3 32 32 32s32-14.3 32-32l0-64 64 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L32 32zM64 352c0-17.7-14.3-32-32-32S0 334.3 0 352l0 96c0 17.7 14.3 32 32 32l96 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-64 0 0-64zM320 32c-17.7 0-32 14.3-32 32s14.3 32 32 32l64 0 0 64c0 17.7 14.3 32 32 32s32-14.3 32-32l0-96c0-17.7-14.3-32-32-32l-96 0zM448 352c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 64-64 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l96 0c17.7 0 32-14.3 32-32l0-96z"/>
22709
+ </symbol>
22710
+ <!-- fit to selection: the same corner brackets as the fit icon,
22711
+ around a marked object. The two sit side by side in the
22712
+ toolbar and have to read as a family, which a borrowed glyph
22713
+ would not. (No backticks in here: the sprite lives inside a
22714
+ template literal.) -->
22715
+ <symbol id="g6-icon-fit-selection" viewBox="0 0 448 512">
22716
+ <path fill="currentColor" d="M32 32C14.3 32 0 46.3 0 64l0 96c0 17.7 14.3 32 32 32s32-14.3 32-32l0-64 64 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L32 32zM64 352c0-17.7-14.3-32-32-32S0 334.3 0 352l0 96c0 17.7 14.3 32 32 32l96 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-64 0 0-64zM320 32c-17.7 0-32 14.3-32 32s14.3 32 32 32l64 0 0 64c0 17.7 14.3 32 32 32s32-14.3 32-32l0-96c0-17.7-14.3-32-32-32l-96 0zM448 352c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 64-64 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l96 0c17.7 0 32-14.3 32-32l0-96z"/>
22717
+ <rect fill="currentColor" x="144" y="176" width="160" height="160" rx="24"/>
22718
+ </symbol>
22719
+ <!-- crosshairs (center) -->
22720
+ <symbol id="g6-icon-center" viewBox="0 0 576 512">
22721
+ <path fill="currentColor" d="M288-16c17.7 0 32 14.3 32 32l0 18.3c98.1 14 175.7 91.6 189.7 189.7l18.3 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-18.3 0c-14 98.1-91.6 175.7-189.7 189.7l0 18.3c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-18.3C157.9 463.7 80.3 386.1 66.3 288L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l18.3 0C80.3 125.9 157.9 48.3 256 34.3L256 16c0-17.7 14.3-32 32-32zM131.2 288c12.7 62.7 62.1 112.1 124.8 124.8l0-12.8c0-17.7 14.3-32 32-32s32 14.3 32 32l0 12.8c62.7-12.7 112.1-62.1 124.8-124.8L432 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l12.8 0C432.1 161.3 382.7 111.9 320 99.2l0 12.8c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-12.8C193.3 111.9 143.9 161.3 131.2 224l12.8 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-12.8 0zM288 208a48 48 0 1 1 0 96 48 48 0 1 1 0-96z"/>
22722
+ </symbol>
22723
+ <!-- up-right-and-down-left-from-center (enter fullscreen) -->
22724
+ <symbol id="g6-icon-fullscreen" viewBox="0 0 512 512">
22725
+ <path fill="currentColor" d="M344 0L488 0c13.3 0 24 10.7 24 24l0 144c0 9.7-5.8 18.5-14.8 22.2s-19.3 1.7-26.2-5.2l-39-39-87 87c-9.4 9.4-24.6 9.4-33.9 0l-32-32c-9.4-9.4-9.4-24.6 0-33.9l87-87-39-39c-6.9-6.9-8.9-17.2-5.2-26.2S334.3 0 344 0zM168 512L24 512c-13.3 0-24-10.7-24-24L0 344c0-9.7 5.8-18.5 14.8-22.2S34.1 320.2 41 327l39 39 87-87c9.4-9.4 24.6-9.4 33.9 0l32 32c9.4 9.4 9.4 24.6 0 33.9l-87 87 39 39c6.9 6.9 8.9 17.2 5.2 26.2S177.7 512 168 512z"/>
22726
+ </symbol>
22727
+ <!-- down-left-and-up-right-to-center (exit fullscreen) -->
22728
+ <symbol id="g6-icon-fullscreen-exit" viewBox="0 0 512 512">
22729
+ <path fill="currentColor" d="M439.5 7c9.4-9.4 24.6-9.4 33.9 0l32 32c9.4 9.4 9.4 24.6 0 33.9l-87 87 39 39c6.9 6.9 8.9 17.2 5.2 26.2S450.2 240 440.5 240l-144 0c-13.3 0-24-10.7-24-24l0-144c0-9.7 5.8-18.5 14.8-22.2s19.3-1.7 26.2 5.2l39 39 87-87zM72.5 272l144 0c13.3 0 24 10.7 24 24l0 144c0 9.7-5.8 18.5-14.8 22.2s-19.3 1.7-26.2-5.2l-39-39-87 87c-9.4 9.4-24.6 9.4-33.9 0l-32-32c-9.4-9.4-9.4-24.6 0-33.9l87-87-39-39c-6.9-6.9-8.9-17.2-5.2-26.2S62.8 272 72.5 272z"/>
22730
+ </symbol>
22731
+ <!-- arrow-rotate-left (undo) -->
22732
+ <symbol id="g6-icon-undo" viewBox="0 0 512 512">
22733
+ <path fill="currentColor" d="M256 64c-56.8 0-107.9 24.7-143.1 64l47.1 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 192c-17.7 0-32-14.3-32-32L0 32C0 14.3 14.3 0 32 0S64 14.3 64 32l0 54.7C110.9 33.6 179.5 0 256 0 397.4 0 512 114.6 512 256S397.4 512 256 512c-87 0-163.9-43.4-210.1-109.7-10.1-14.5-6.6-34.4 7.9-44.6s34.4-6.6 44.6 7.9c34.8 49.8 92.4 82.3 157.6 82.3 106 0 192-86 192-192S362 64 256 64z"/>
22734
+ </symbol>
22735
+ <!-- arrow-rotate-right (redo) -->
22736
+ <symbol id="g6-icon-redo" viewBox="0 0 512 512">
22737
+ <path fill="currentColor" d="M436.7 74.7L448 85.4 448 32c0-17.7 14.3-32 32-32s32 14.3 32 32l0 128c0 17.7-14.3 32-32 32l-128 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l47.9 0-7.6-7.2c-.2-.2-.4-.4-.6-.6-75-75-196.5-75-271.5 0s-75 196.5 0 271.5 196.5 75 271.5 0c8.2-8.2 15.5-16.9 21.9-26.1 10.1-14.5 30.1-18 44.6-7.9s18 30.1 7.9 44.6c-8.5 12.2-18.2 23.8-29.1 34.7-100 100-262.1 100-362 0S-25 175 75 75c99.9-99.9 261.7-100 361.7-.3z"/>
22738
+ </symbol>
22739
+ <!-- pen (edit node) -->
22740
+ <symbol id="g6-icon-edit" viewBox="0 0 512 512">
22741
+ <path fill="currentColor" d="M352.9 21.2L308 66.1 445.9 204 490.8 159.1C504.4 145.6 512 127.2 512 108s-7.6-37.6-21.2-51.1L455.1 21.2C441.6 7.6 423.2 0 404 0s-37.6 7.6-51.1 21.2zM274.1 100L58.9 315.1c-10.7 10.7-18.5 24.1-22.6 38.7L.9 481.6c-2.3 8.3 0 17.3 6.2 23.4s15.1 8.5 23.4 6.2l127.8-35.5c14.6-4.1 27.9-11.8 38.7-22.6L412 237.9 274.1 100z"/>
22742
+ </symbol>
22743
+ <!-- trash-can (delete) -->
22744
+ <symbol id="g6-icon-delete" viewBox="0 0 448 512">
22745
+ <path fill="currentColor" d="M136.7 5.9C141.1-7.2 153.3-16 167.1-16l113.9 0c13.8 0 26 8.8 30.4 21.9L320 32 416 32c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 96C14.3 96 0 81.7 0 64S14.3 32 32 32l96 0 8.7-26.1zM32 144l384 0 0 304c0 35.3-28.7 64-64 64L96 512c-35.3 0-64-28.7-64-64l0-304zm88 64c-13.3 0-24 10.7-24 24l0 192c0 13.3 10.7 24 24 24s24-10.7 24-24l0-192c0-13.3-10.7-24-24-24zm104 0c-13.3 0-24 10.7-24 24l0 192c0 13.3 10.7 24 24 24s24-10.7 24-24l0-192c0-13.3-10.7-24-24-24zm104 0c-13.3 0-24 10.7-24 24l0 192c0 13.3 10.7 24 24 24s24-10.7 24-24l0-192c0-13.3-10.7-24-24-24z"/>
22746
+ </symbol>
22747
+ <!-- link (link nodes) -->
22748
+ <symbol id="g6-icon-link" viewBox="0 0 576 512">
22749
+ <path fill="currentColor" d="M419.5 96c-16.6 0-32.7 4.5-46.8 12.7-15.8-16-34.2-29.4-54.5-39.5 28.2-24 64.1-37.2 101.3-37.2 86.4 0 156.5 70 156.5 156.5 0 41.5-16.5 81.3-45.8 110.6l-71.1 71.1c-29.3 29.3-69.1 45.8-110.6 45.8-86.4 0-156.5-70-156.5-156.5 0-1.5 0-3 .1-4.5 .5-17.7 15.2-31.6 32.9-31.1s31.6 15.2 31.1 32.9c0 .9 0 1.8 0 2.6 0 51.1 41.4 92.5 92.5 92.5 24.5 0 48-9.7 65.4-27.1l71.1-71.1c17.3-17.3 27.1-40.9 27.1-65.4 0-51.1-41.4-92.5-92.5-92.5zM275.2 173.3c-1.9-.8-3.8-1.9-5.5-3.1-12.6-6.5-27-10.2-42.1-10.2-24.5 0-48 9.7-65.4 27.1L91.1 258.2c-17.3 17.3-27.1 40.9-27.1 65.4 0 51.1 41.4 92.5 92.5 92.5 16.5 0 32.6-4.4 46.7-12.6 15.8 16 34.2 29.4 54.6 39.5-28.2 23.9-64 37.2-101.3 37.2-86.4 0-156.5-70-156.5-156.5 0-41.5 16.5-81.3 45.8-110.6l71.1-71.1c29.3-29.3 69.1-45.8 110.6-45.8 86.6 0 156.5 70.6 156.5 156.9 0 1.3 0 2.6 0 3.9-.4 17.7-15.1 31.6-32.8 31.2s-31.6-15.1-31.2-32.8c0-.8 0-1.5 0-2.3 0-33.7-18-63.3-44.8-79.6z"/>
22750
+ </symbol>
22751
+ <!-- link-slash (unlink) -->
22752
+ <symbol id="g6-icon-unlink" viewBox="0 0 576 512">
22753
+ <path fill="currentColor" d="M41-24.9c-9.4-9.4-24.6-9.4-33.9 0S-2.3-.3 7 9.1l528 528c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-122-122c4.2-3.4 8.3-7.1 12.1-10.9l71.1-71.1c29.3-29.3 45.8-69.1 45.8-110.6 0-86.4-70-156.5-156.5-156.5-37.3 0-73.1 13.3-101.3 37.2 20.3 10.1 38.7 23.5 54.5 39.5 14.1-8.3 30.2-12.7 46.8-12.7 51.1 0 92.5 41.4 92.5 92.5 0 24.5-9.7 48-27.1 65.4l-71.1 71.1c-3.9 3.9-8.1 7.4-12.6 10.5l-47.5-47.5c16.5-.9 29.7-14.4 30.2-31.1 0-1.3 0-2.6 0-3.9 0-86.3-69.9-156.9-156.5-156.9-19.2 0-37.9 3.5-55.5 10.2L41-24.9zM225.9 160c.6 0 1.1 0 1.7 0 15.1 0 29.5 3.7 42.1 10.2 1.8 1.2 3.6 2.3 5.5 3.1 26.8 16.3 44.8 45.9 44.8 79.6 0 .4 0 .8 0 1.2L225.9 160zM346.2 416L192 261.8c1.2 84.6 69.6 152.9 154.1 154.1zM139.7 209.5l-45.3-45.3-48.6 48.6c-29.3 29.3-45.8 69.1-45.8 110.6 0 86.4 70 156.5 156.5 156.5 37.2 0 73.1-13.3 101.3-37.2-20.3-10.1-38.8-23.5-54.6-39.5-14 8.2-30.1 12.6-46.7 12.6-51.1 0-92.5-41.4-92.5-92.5 0-24.5 9.7-48 27.1-65.4l48.6-48.6z"/>
22754
+ </symbol>
22755
+ <!-- play (run node) -->
22756
+ <symbol id="g6-icon-run" viewBox="0 0 448 512">
22757
+ <path fill="currentColor" d="M91.2 36.9c-12.4-6.8-27.4-6.5-39.6 .7S32 57.9 32 72l0 368c0 14.1 7.5 27.2 19.6 34.4s27.2 7.5 39.6 .7l336-184c12.8-7 20.8-20.5 20.8-35.1s-8-28.1-20.8-35.1l-336-184z"/>
22758
+ </symbol>
22759
+ <!-- clone (copy size to other nodes/ports) -->
22760
+ <symbol id="g6-icon-resize" viewBox="0 0 512 512">
22761
+ <path fill="currentColor" d="M288 448l-224 0 0-224 48 0 0-64-48 0c-35.3 0-64 28.7-64 64L0 448c0 35.3 28.7 64 64 64l224 0c35.3 0 64-28.7 64-64l0-48-64 0 0 48zm-64-96l224 0c35.3 0 64-28.7 64-64l0-224c0-35.3-28.7-64-64-64L224 0c-35.3 0-64 28.7-64 64l0 224c0 35.3 28.7 64 64 64z"/>
22762
+ </symbol>
22763
+ <!-- plus (create node). Deliberately NOT the FA7 solid plus:
22764
+ its arms are ~14% of the width and read thin next to the
22765
+ other solid glyphs. Bold geometric plus (~23% arm
22766
+ thickness) with long arms (32..480) so it reads as a "+",
22767
+ not a stubby Red-Cross square. -->
22768
+ <symbol id="g6-icon-plus" viewBox="0 0 512 512">
22769
+ <path fill="currentColor" d="M316 32 L316 196 L480 196 L480 316 L316 316 L316 480 L196 480 L196 316 L32 316 L32 196 L196 196 L196 32 Z"/>
22770
+ </symbol>
22771
+ <!-- ellipsis-vertical (unfold the floating toolbar).
22772
+ The strip it stands for is a vertical stack, and a vertical
22773
+ ellipsis is what "there is more of this here" is drawn as
22774
+ everywhere else. -->
22775
+ <symbol id="g6-icon-toolbar-show" viewBox="0 0 128 512">
22776
+ <path fill="currentColor" d="M64 360a56 56 0 1 0 0 112 56 56 0 1 0 0-112zm0-160a56 56 0 1 0 0 112 56 56 0 1 0 0-112zM120 96A56 56 0 1 0 8 96a56 56 0 1 0 112 0z"/>
22777
+ </symbol>
22778
+ <!-- xmark (fold the floating toolbar away).
22779
+ Not a chevron: the two toolbars sit on OPPOSITE edges, so a
22780
+ direction would point the wrong way on one of them. What the
22781
+ button does is close an overlay, and that is an x. -->
22782
+ <symbol id="g6-icon-toolbar-hide" viewBox="0 0 384 512">
22783
+ <path fill="currentColor" d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"/>
22784
+ </symbol>
22785
+ <!-- dashed marquee (selection mode).
22786
+ The band ITSELF, because that is what the button turns on: a
22787
+ drag on the canvas draws one and a tap picks a card. Not the
22788
+ fit-to-selection glyph next to it in the other toolbar -- that
22789
+ one is solid brackets around a solid object and means "put the
22790
+ camera on what is picked", which is the opposite end of the
22791
+ gesture. Dashes: 16 segments of 59 with gaps of 36 over a
22792
+ perimeter of 1520, so they land on the corners. -->
22793
+ <symbol id="g6-icon-select-mode" viewBox="0 0 512 512">
22794
+ <rect x="46" y="86" width="420" height="340" fill="none"
22795
+ stroke="currentColor" stroke-width="40"
22796
+ stroke-dasharray="59 36"/>
22797
+ </symbol>
22798
+ <!-- location-crosshairs (anchor the camera on one element).
22799
+ The SAME path as the DOM toolbars and their yi-location-crosshairs
22800
+ mask: the two toolbars sit in one console, and a control that
22801
+ does one thing has to be drawn one way. -->
22802
+ <symbol id="g6-icon-anchor" viewBox="0 0 576 512">
22803
+ <path fill="currentColor" d="M288-16c17.7 0 32 14.3 32 32l0 18.3c98.1 14 175.7 91.6 189.7 189.7l18.3 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-18.3 0c-14 98.1-91.6 175.7-189.7 189.7l0 18.3c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-18.3C157.9 463.7 80.3 386.1 66.3 288L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l18.3 0C80.3 125.9 157.9 48.3 256 34.3L256 16c0-17.7 14.3-32 32-32zM128 256a160 160 0 1 0 320 0 160 160 0 1 0 -320 0zm160-96a96 96 0 1 1 0 192 96 96 0 1 1 0-192z"/>
22804
+ </symbol>
22805
+ <!-- floppy-disk (save) -->
22806
+ <symbol id="g6-icon-save" viewBox="0 0 448 512">
22807
+ <path fill="currentColor" d="M64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l320 0c35.3 0 64-28.7 64-64l0-242.7c0-17-6.7-33.3-18.7-45.3L352 50.7C340 38.7 323.7 32 306.7 32L64 32zm32 96c0-17.7 14.3-32 32-32l160 0c17.7 0 32 14.3 32 32l0 64c0 17.7-14.3 32-32 32l-160 0c-17.7 0-32-14.3-32-32l0-64zM224 288a64 64 0 1 1 0 128 64 64 0 1 1 0-128z"/>
22808
+ </symbol>
22809
+ </svg>`;
22810
+ function inject_svg_icons() {
22811
+ if (document.getElementById(CUSTOM_SVG_ICONS_ID)) return;
22812
+ const div = document.createElement("div");
22813
+ div.id = CUSTOM_SVG_ICONS_ID;
22814
+ div.style.display = "none";
22815
+ div.innerHTML = ICONS;
22816
+ document.body.appendChild(div);
22817
+ }
22818
+ var __icon_defined__ = {};
22819
+ function yui_icon_is_defined(name) {
22820
+ if (!name || typeof name !== "string") return false;
22821
+ if (__icon_defined__[name] !== void 0) return __icon_defined__[name];
22822
+ let defined = false;
22823
+ try {
22824
+ const el = document.createElement("i");
22825
+ el.className = name;
22826
+ el.style.position = "absolute";
22827
+ el.style.visibility = "hidden";
22828
+ el.style.pointerEvents = "none";
22829
+ document.body.appendChild(el);
22830
+ const st = window.getComputedStyle(el, "::before");
22831
+ const mask = st.maskImage || st.webkitMaskImage || "";
22832
+ defined = !!mask && mask !== "none";
22833
+ document.body.removeChild(el);
22834
+ } catch (e) {
22835
+ defined = false;
22836
+ }
22837
+ __icon_defined__[name] = defined;
22838
+ return defined;
22839
+ }
22840
+ //#endregion
22661
22841
  //#region src/yui_row_search.js
22662
22842
  /***********************************************************************
22663
22843
  * yui_row_search.js
@@ -23738,6 +23918,11 @@ function create_tabulator(gobj) {
23738
23918
  hozAlign = "center";
23739
23919
  colFormatter = "color";
23740
23920
  break;
23921
+ case "icon":
23922
+ hozAlign = "center";
23923
+ vertAlign = "middle";
23924
+ colFormatter = icon_formatter;
23925
+ break;
23741
23926
  case "object":
23742
23927
  case "dict":
23743
23928
  case "template":
@@ -23961,6 +24146,39 @@ function table__destroy(gobj) {
23961
24146
  }
23962
24147
  }
23963
24148
  /************************************************************
24149
+ * Cell of a col flagged `icon`: the value is the NAME of an
24150
+ * icon of the app's set ("yi-bolt"), so it is DRAWN.
24151
+ *
24152
+ * Built as a DOM node and not as an HTML string: the value is
24153
+ * raw record data and must never be parsed as markup -- and
24154
+ * here it also becomes a CSS class, so it is filtered to the
24155
+ * shape of a class name before it gets near one.
24156
+ *
24157
+ * A name the set does not carry falls back to the TEXT of it.
24158
+ * The catch-all rule `[class^="yi-"]::before` paints a
24159
+ * currentColor box for any name, so drawing it anyway would
24160
+ * render a solid square -- a glyph nobody recognises rather
24161
+ * than a mistake somebody can fix.
24162
+ ************************************************************/
24163
+ function icon_formatter(cell) {
24164
+ let name = cell.getValue();
24165
+ if (!(0, _yuneta_gobj_js.is_string)(name) || (0, _yuneta_gobj_js.empty_string)(name)) return "";
24166
+ name = name.trim();
24167
+ if (!/^[a-z0-9-]+$/.test(name) || !yui_icon_is_defined(name)) return (0, _yuneta_gobj_js.createElement2)([
24168
+ "span",
24169
+ {
24170
+ class: "ICON_CELL_UNKNOWN is-size-7 has-text-grey",
24171
+ title: name
24172
+ },
24173
+ name
24174
+ ]);
24175
+ return (0, _yuneta_gobj_js.createElement2)(["span", {
24176
+ class: `ICON_CELL ${name}`,
24177
+ title: name,
24178
+ "aria-label": name
24179
+ }]);
24180
+ }
24181
+ /************************************************************
23964
24182
  * Cell of a col holding a JSON document (dict/list/blob/
23965
24183
  * template/coordinates/…): a one-line truncated preview,
23966
24184
  * marked as a link because the click opens the whole value
@@ -24072,6 +24290,7 @@ function transform__treedb_value_2_table_value(gobj, col, value, row, field) {
24072
24290
  }
24073
24291
  break;
24074
24292
  case "color": break;
24293
+ case "icon": break;
24075
24294
  case "image": break;
24076
24295
  default: (0, _yuneta_gobj_js.log_error)(`transform__treedb_value_2_table_value() unhandled type '${field_desc.type}' (real_type='${field_desc.real_type}') for field '${field}', topic ${priv.topic_name}`);
24077
24296
  }
@@ -52405,160 +52624,6 @@ Sector.PARSED_STYLE_LIST = new Set([].concat(_toConsumableArray(Path.PARSED_STYL
52405
52624
  "endAngle"
52406
52625
  ]));
52407
52626
  //#endregion
52408
- //#region src/lib_icons.js
52409
- /*********************************************************
52410
- * lib_icons.js
52411
- *
52412
- * Two icon systems are managed here:
52413
- *
52414
- * 1. FA-style CSS icons (yui_icons.css)
52415
- * Usage: <i class="yi-save"></i>
52416
- * Color: inherits currentColor from parent via CSS mask.
52417
- *
52418
- * 2. SVG symbol icons for G6 toolbar (and any other component
52419
- * that uses <use xlink:href="#id">).
52420
- * Symbols are injected once into the DOM.
52421
- * All symbol ids are prefixed with "g6-icon-" to avoid
52422
- * conflicts with other DOM elements.
52423
- * Icon paths come from:
52424
- * fontawesome-free-7.1.0-web/sprites/solid.svg
52425
- *
52426
- * G6 toolbar items are managed via CSS class names (className
52427
- * field in getItems()) using YuiToolbar in c_g6_nodes_tree.js.
52428
- * This lets lib_graph.js state functions (set_submit_state,
52429
- * disableElements, …) work on toolbar icons exactly like on
52430
- * regular Bulma/FA buttons — no icon-specific helpers needed.
52431
- *
52432
- * Copyright (c) 2025-2026, ArtGins.
52433
- * All Rights Reserved.
52434
- *********************************************************/
52435
- var CUSTOM_SVG_ICONS_ID = "g6-custom-svgicons";
52436
- var ICONS = `<svg xmlns="http://www.w3.org/2000/svg">
52437
- <!-- magnifying-glass-plus -->
52438
- <symbol id="g6-icon-zoom-in" viewBox="0 0 512 512">
52439
- <path fill="currentColor" d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376C296.3 401.1 253.9 416 208 416 93.1 416 0 322.9 0 208S93.1 0 208 0 416 93.1 416 208zM208 112c-13.3 0-24 10.7-24 24l0 48-48 0c-13.3 0-24 10.7-24 24s10.7 24 24 24l48 0 0 48c0 13.3 10.7 24 24 24s24-10.7 24-24l0-48 48 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-48 0 0-48c0-13.3-10.7-24-24-24z"/>
52440
- </symbol>
52441
- <!-- magnifying-glass-minus -->
52442
- <symbol id="g6-icon-zoom-out" viewBox="0 0 512 512">
52443
- <path fill="currentColor" d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376C296.3 401.1 253.9 416 208 416 93.1 416 0 322.9 0 208S93.1 0 208 0 416 93.1 416 208zM136 184c-13.3 0-24 10.7-24 24s10.7 24 24 24l144 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-144 0z"/>
52444
- </symbol>
52445
- <!-- house (reset zoom: back to original 100% view) -->
52446
- <symbol id="g6-icon-home" viewBox="0 0 512 512">
52447
- <path fill="currentColor" d="M277.8 8.6c-12.3-11.4-31.3-11.4-43.5 0l-224 208c-9.6 9-12.8 22.9-8 35.1S18.8 272 32 272l16 0 0 176c0 35.3 28.7 64 64 64l288 0c35.3 0 64-28.7 64-64l0-176 16 0c13.2 0 25-8.1 29.8-20.3s1.6-26.2-8-35.1l-224-208zM240 320l32 0c26.5 0 48 21.5 48 48l0 96-128 0 0-96c0-26.5 21.5-48 48-48z"/>
52448
- </symbol>
52449
- <!-- expand (zoom to fit) -->
52450
- <symbol id="g6-icon-fit" viewBox="0 0 448 512">
52451
- <path fill="currentColor" d="M32 32C14.3 32 0 46.3 0 64l0 96c0 17.7 14.3 32 32 32s32-14.3 32-32l0-64 64 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L32 32zM64 352c0-17.7-14.3-32-32-32S0 334.3 0 352l0 96c0 17.7 14.3 32 32 32l96 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-64 0 0-64zM320 32c-17.7 0-32 14.3-32 32s14.3 32 32 32l64 0 0 64c0 17.7 14.3 32 32 32s32-14.3 32-32l0-96c0-17.7-14.3-32-32-32l-96 0zM448 352c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 64-64 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l96 0c17.7 0 32-14.3 32-32l0-96z"/>
52452
- </symbol>
52453
- <!-- fit to selection: the same corner brackets as the fit icon,
52454
- around a marked object. The two sit side by side in the
52455
- toolbar and have to read as a family, which a borrowed glyph
52456
- would not. (No backticks in here: the sprite lives inside a
52457
- template literal.) -->
52458
- <symbol id="g6-icon-fit-selection" viewBox="0 0 448 512">
52459
- <path fill="currentColor" d="M32 32C14.3 32 0 46.3 0 64l0 96c0 17.7 14.3 32 32 32s32-14.3 32-32l0-64 64 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L32 32zM64 352c0-17.7-14.3-32-32-32S0 334.3 0 352l0 96c0 17.7 14.3 32 32 32l96 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-64 0 0-64zM320 32c-17.7 0-32 14.3-32 32s14.3 32 32 32l64 0 0 64c0 17.7 14.3 32 32 32s32-14.3 32-32l0-96c0-17.7-14.3-32-32-32l-96 0zM448 352c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 64-64 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l96 0c17.7 0 32-14.3 32-32l0-96z"/>
52460
- <rect fill="currentColor" x="144" y="176" width="160" height="160" rx="24"/>
52461
- </symbol>
52462
- <!-- crosshairs (center) -->
52463
- <symbol id="g6-icon-center" viewBox="0 0 576 512">
52464
- <path fill="currentColor" d="M288-16c17.7 0 32 14.3 32 32l0 18.3c98.1 14 175.7 91.6 189.7 189.7l18.3 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-18.3 0c-14 98.1-91.6 175.7-189.7 189.7l0 18.3c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-18.3C157.9 463.7 80.3 386.1 66.3 288L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l18.3 0C80.3 125.9 157.9 48.3 256 34.3L256 16c0-17.7 14.3-32 32-32zM131.2 288c12.7 62.7 62.1 112.1 124.8 124.8l0-12.8c0-17.7 14.3-32 32-32s32 14.3 32 32l0 12.8c62.7-12.7 112.1-62.1 124.8-124.8L432 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l12.8 0C432.1 161.3 382.7 111.9 320 99.2l0 12.8c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-12.8C193.3 111.9 143.9 161.3 131.2 224l12.8 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-12.8 0zM288 208a48 48 0 1 1 0 96 48 48 0 1 1 0-96z"/>
52465
- </symbol>
52466
- <!-- up-right-and-down-left-from-center (enter fullscreen) -->
52467
- <symbol id="g6-icon-fullscreen" viewBox="0 0 512 512">
52468
- <path fill="currentColor" d="M344 0L488 0c13.3 0 24 10.7 24 24l0 144c0 9.7-5.8 18.5-14.8 22.2s-19.3 1.7-26.2-5.2l-39-39-87 87c-9.4 9.4-24.6 9.4-33.9 0l-32-32c-9.4-9.4-9.4-24.6 0-33.9l87-87-39-39c-6.9-6.9-8.9-17.2-5.2-26.2S334.3 0 344 0zM168 512L24 512c-13.3 0-24-10.7-24-24L0 344c0-9.7 5.8-18.5 14.8-22.2S34.1 320.2 41 327l39 39 87-87c9.4-9.4 24.6-9.4 33.9 0l32 32c9.4 9.4 9.4 24.6 0 33.9l-87 87 39 39c6.9 6.9 8.9 17.2 5.2 26.2S177.7 512 168 512z"/>
52469
- </symbol>
52470
- <!-- down-left-and-up-right-to-center (exit fullscreen) -->
52471
- <symbol id="g6-icon-fullscreen-exit" viewBox="0 0 512 512">
52472
- <path fill="currentColor" d="M439.5 7c9.4-9.4 24.6-9.4 33.9 0l32 32c9.4 9.4 9.4 24.6 0 33.9l-87 87 39 39c6.9 6.9 8.9 17.2 5.2 26.2S450.2 240 440.5 240l-144 0c-13.3 0-24-10.7-24-24l0-144c0-9.7 5.8-18.5 14.8-22.2s19.3-1.7 26.2 5.2l39 39 87-87zM72.5 272l144 0c13.3 0 24 10.7 24 24l0 144c0 9.7-5.8 18.5-14.8 22.2s-19.3 1.7-26.2-5.2l-39-39-87 87c-9.4 9.4-24.6 9.4-33.9 0l-32-32c-9.4-9.4-9.4-24.6 0-33.9l87-87-39-39c-6.9-6.9-8.9-17.2-5.2-26.2S62.8 272 72.5 272z"/>
52473
- </symbol>
52474
- <!-- arrow-rotate-left (undo) -->
52475
- <symbol id="g6-icon-undo" viewBox="0 0 512 512">
52476
- <path fill="currentColor" d="M256 64c-56.8 0-107.9 24.7-143.1 64l47.1 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 192c-17.7 0-32-14.3-32-32L0 32C0 14.3 14.3 0 32 0S64 14.3 64 32l0 54.7C110.9 33.6 179.5 0 256 0 397.4 0 512 114.6 512 256S397.4 512 256 512c-87 0-163.9-43.4-210.1-109.7-10.1-14.5-6.6-34.4 7.9-44.6s34.4-6.6 44.6 7.9c34.8 49.8 92.4 82.3 157.6 82.3 106 0 192-86 192-192S362 64 256 64z"/>
52477
- </symbol>
52478
- <!-- arrow-rotate-right (redo) -->
52479
- <symbol id="g6-icon-redo" viewBox="0 0 512 512">
52480
- <path fill="currentColor" d="M436.7 74.7L448 85.4 448 32c0-17.7 14.3-32 32-32s32 14.3 32 32l0 128c0 17.7-14.3 32-32 32l-128 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l47.9 0-7.6-7.2c-.2-.2-.4-.4-.6-.6-75-75-196.5-75-271.5 0s-75 196.5 0 271.5 196.5 75 271.5 0c8.2-8.2 15.5-16.9 21.9-26.1 10.1-14.5 30.1-18 44.6-7.9s18 30.1 7.9 44.6c-8.5 12.2-18.2 23.8-29.1 34.7-100 100-262.1 100-362 0S-25 175 75 75c99.9-99.9 261.7-100 361.7-.3z"/>
52481
- </symbol>
52482
- <!-- pen (edit node) -->
52483
- <symbol id="g6-icon-edit" viewBox="0 0 512 512">
52484
- <path fill="currentColor" d="M352.9 21.2L308 66.1 445.9 204 490.8 159.1C504.4 145.6 512 127.2 512 108s-7.6-37.6-21.2-51.1L455.1 21.2C441.6 7.6 423.2 0 404 0s-37.6 7.6-51.1 21.2zM274.1 100L58.9 315.1c-10.7 10.7-18.5 24.1-22.6 38.7L.9 481.6c-2.3 8.3 0 17.3 6.2 23.4s15.1 8.5 23.4 6.2l127.8-35.5c14.6-4.1 27.9-11.8 38.7-22.6L412 237.9 274.1 100z"/>
52485
- </symbol>
52486
- <!-- trash-can (delete) -->
52487
- <symbol id="g6-icon-delete" viewBox="0 0 448 512">
52488
- <path fill="currentColor" d="M136.7 5.9C141.1-7.2 153.3-16 167.1-16l113.9 0c13.8 0 26 8.8 30.4 21.9L320 32 416 32c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 96C14.3 96 0 81.7 0 64S14.3 32 32 32l96 0 8.7-26.1zM32 144l384 0 0 304c0 35.3-28.7 64-64 64L96 512c-35.3 0-64-28.7-64-64l0-304zm88 64c-13.3 0-24 10.7-24 24l0 192c0 13.3 10.7 24 24 24s24-10.7 24-24l0-192c0-13.3-10.7-24-24-24zm104 0c-13.3 0-24 10.7-24 24l0 192c0 13.3 10.7 24 24 24s24-10.7 24-24l0-192c0-13.3-10.7-24-24-24zm104 0c-13.3 0-24 10.7-24 24l0 192c0 13.3 10.7 24 24 24s24-10.7 24-24l0-192c0-13.3-10.7-24-24-24z"/>
52489
- </symbol>
52490
- <!-- link (link nodes) -->
52491
- <symbol id="g6-icon-link" viewBox="0 0 576 512">
52492
- <path fill="currentColor" d="M419.5 96c-16.6 0-32.7 4.5-46.8 12.7-15.8-16-34.2-29.4-54.5-39.5 28.2-24 64.1-37.2 101.3-37.2 86.4 0 156.5 70 156.5 156.5 0 41.5-16.5 81.3-45.8 110.6l-71.1 71.1c-29.3 29.3-69.1 45.8-110.6 45.8-86.4 0-156.5-70-156.5-156.5 0-1.5 0-3 .1-4.5 .5-17.7 15.2-31.6 32.9-31.1s31.6 15.2 31.1 32.9c0 .9 0 1.8 0 2.6 0 51.1 41.4 92.5 92.5 92.5 24.5 0 48-9.7 65.4-27.1l71.1-71.1c17.3-17.3 27.1-40.9 27.1-65.4 0-51.1-41.4-92.5-92.5-92.5zM275.2 173.3c-1.9-.8-3.8-1.9-5.5-3.1-12.6-6.5-27-10.2-42.1-10.2-24.5 0-48 9.7-65.4 27.1L91.1 258.2c-17.3 17.3-27.1 40.9-27.1 65.4 0 51.1 41.4 92.5 92.5 92.5 16.5 0 32.6-4.4 46.7-12.6 15.8 16 34.2 29.4 54.6 39.5-28.2 23.9-64 37.2-101.3 37.2-86.4 0-156.5-70-156.5-156.5 0-41.5 16.5-81.3 45.8-110.6l71.1-71.1c29.3-29.3 69.1-45.8 110.6-45.8 86.6 0 156.5 70.6 156.5 156.9 0 1.3 0 2.6 0 3.9-.4 17.7-15.1 31.6-32.8 31.2s-31.6-15.1-31.2-32.8c0-.8 0-1.5 0-2.3 0-33.7-18-63.3-44.8-79.6z"/>
52493
- </symbol>
52494
- <!-- link-slash (unlink) -->
52495
- <symbol id="g6-icon-unlink" viewBox="0 0 576 512">
52496
- <path fill="currentColor" d="M41-24.9c-9.4-9.4-24.6-9.4-33.9 0S-2.3-.3 7 9.1l528 528c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-122-122c4.2-3.4 8.3-7.1 12.1-10.9l71.1-71.1c29.3-29.3 45.8-69.1 45.8-110.6 0-86.4-70-156.5-156.5-156.5-37.3 0-73.1 13.3-101.3 37.2 20.3 10.1 38.7 23.5 54.5 39.5 14.1-8.3 30.2-12.7 46.8-12.7 51.1 0 92.5 41.4 92.5 92.5 0 24.5-9.7 48-27.1 65.4l-71.1 71.1c-3.9 3.9-8.1 7.4-12.6 10.5l-47.5-47.5c16.5-.9 29.7-14.4 30.2-31.1 0-1.3 0-2.6 0-3.9 0-86.3-69.9-156.9-156.5-156.9-19.2 0-37.9 3.5-55.5 10.2L41-24.9zM225.9 160c.6 0 1.1 0 1.7 0 15.1 0 29.5 3.7 42.1 10.2 1.8 1.2 3.6 2.3 5.5 3.1 26.8 16.3 44.8 45.9 44.8 79.6 0 .4 0 .8 0 1.2L225.9 160zM346.2 416L192 261.8c1.2 84.6 69.6 152.9 154.1 154.1zM139.7 209.5l-45.3-45.3-48.6 48.6c-29.3 29.3-45.8 69.1-45.8 110.6 0 86.4 70 156.5 156.5 156.5 37.2 0 73.1-13.3 101.3-37.2-20.3-10.1-38.8-23.5-54.6-39.5-14 8.2-30.1 12.6-46.7 12.6-51.1 0-92.5-41.4-92.5-92.5 0-24.5 9.7-48 27.1-65.4l48.6-48.6z"/>
52497
- </symbol>
52498
- <!-- play (run node) -->
52499
- <symbol id="g6-icon-run" viewBox="0 0 448 512">
52500
- <path fill="currentColor" d="M91.2 36.9c-12.4-6.8-27.4-6.5-39.6 .7S32 57.9 32 72l0 368c0 14.1 7.5 27.2 19.6 34.4s27.2 7.5 39.6 .7l336-184c12.8-7 20.8-20.5 20.8-35.1s-8-28.1-20.8-35.1l-336-184z"/>
52501
- </symbol>
52502
- <!-- clone (copy size to other nodes/ports) -->
52503
- <symbol id="g6-icon-resize" viewBox="0 0 512 512">
52504
- <path fill="currentColor" d="M288 448l-224 0 0-224 48 0 0-64-48 0c-35.3 0-64 28.7-64 64L0 448c0 35.3 28.7 64 64 64l224 0c35.3 0 64-28.7 64-64l0-48-64 0 0 48zm-64-96l224 0c35.3 0 64-28.7 64-64l0-224c0-35.3-28.7-64-64-64L224 0c-35.3 0-64 28.7-64 64l0 224c0 35.3 28.7 64 64 64z"/>
52505
- </symbol>
52506
- <!-- plus (create node). Deliberately NOT the FA7 solid plus:
52507
- its arms are ~14% of the width and read thin next to the
52508
- other solid glyphs. Bold geometric plus (~23% arm
52509
- thickness) with long arms (32..480) so it reads as a "+",
52510
- not a stubby Red-Cross square. -->
52511
- <symbol id="g6-icon-plus" viewBox="0 0 512 512">
52512
- <path fill="currentColor" d="M316 32 L316 196 L480 196 L480 316 L316 316 L316 480 L196 480 L196 316 L32 316 L32 196 L196 196 L196 32 Z"/>
52513
- </symbol>
52514
- <!-- ellipsis-vertical (unfold the floating toolbar).
52515
- The strip it stands for is a vertical stack, and a vertical
52516
- ellipsis is what "there is more of this here" is drawn as
52517
- everywhere else. -->
52518
- <symbol id="g6-icon-toolbar-show" viewBox="0 0 128 512">
52519
- <path fill="currentColor" d="M64 360a56 56 0 1 0 0 112 56 56 0 1 0 0-112zm0-160a56 56 0 1 0 0 112 56 56 0 1 0 0-112zM120 96A56 56 0 1 0 8 96a56 56 0 1 0 112 0z"/>
52520
- </symbol>
52521
- <!-- xmark (fold the floating toolbar away).
52522
- Not a chevron: the two toolbars sit on OPPOSITE edges, so a
52523
- direction would point the wrong way on one of them. What the
52524
- button does is close an overlay, and that is an x. -->
52525
- <symbol id="g6-icon-toolbar-hide" viewBox="0 0 384 512">
52526
- <path fill="currentColor" d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"/>
52527
- </symbol>
52528
- <!-- dashed marquee (selection mode).
52529
- The band ITSELF, because that is what the button turns on: a
52530
- drag on the canvas draws one and a tap picks a card. Not the
52531
- fit-to-selection glyph next to it in the other toolbar -- that
52532
- one is solid brackets around a solid object and means "put the
52533
- camera on what is picked", which is the opposite end of the
52534
- gesture. Dashes: 16 segments of 59 with gaps of 36 over a
52535
- perimeter of 1520, so they land on the corners. -->
52536
- <symbol id="g6-icon-select-mode" viewBox="0 0 512 512">
52537
- <rect x="46" y="86" width="420" height="340" fill="none"
52538
- stroke="currentColor" stroke-width="40"
52539
- stroke-dasharray="59 36"/>
52540
- </symbol>
52541
- <!-- location-crosshairs (anchor the camera on one element).
52542
- The SAME path as the DOM toolbars and their yi-location-crosshairs
52543
- mask: the two toolbars sit in one console, and a control that
52544
- does one thing has to be drawn one way. -->
52545
- <symbol id="g6-icon-anchor" viewBox="0 0 576 512">
52546
- <path fill="currentColor" d="M288-16c17.7 0 32 14.3 32 32l0 18.3c98.1 14 175.7 91.6 189.7 189.7l18.3 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-18.3 0c-14 98.1-91.6 175.7-189.7 189.7l0 18.3c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-18.3C157.9 463.7 80.3 386.1 66.3 288L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l18.3 0C80.3 125.9 157.9 48.3 256 34.3L256 16c0-17.7 14.3-32 32-32zM128 256a160 160 0 1 0 320 0 160 160 0 1 0 -320 0zm160-96a96 96 0 1 1 0 192 96 96 0 1 1 0-192z"/>
52547
- </symbol>
52548
- <!-- floppy-disk (save) -->
52549
- <symbol id="g6-icon-save" viewBox="0 0 448 512">
52550
- <path fill="currentColor" d="M64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l320 0c35.3 0 64-28.7 64-64l0-242.7c0-17-6.7-33.3-18.7-45.3L352 50.7C340 38.7 323.7 32 306.7 32L64 32zm32 96c0-17.7 14.3-32 32-32l160 0c17.7 0 32 14.3 32 32l0 64c0 17.7-14.3 32-32 32l-160 0c-17.7 0-32-14.3-32-32l0-64zM224 288a64 64 0 1 1 0 128 64 64 0 1 1 0-128z"/>
52551
- </symbol>
52552
- </svg>`;
52553
- function inject_svg_icons() {
52554
- if (document.getElementById(CUSTOM_SVG_ICONS_ID)) return;
52555
- const div = document.createElement("div");
52556
- div.id = CUSTOM_SVG_ICONS_ID;
52557
- div.style.display = "none";
52558
- div.innerHTML = ICONS;
52559
- document.body.appendChild(div);
52560
- }
52561
- //#endregion
52562
52627
  //#region src/g6_brush_select_owned.js
52563
52628
  /***********************************************************************
52564
52629
  * g6_brush_select_owned.js
@@ -6806,6 +6806,7 @@ function build_form_field_conf(gobj, field_desc) {
6806
6806
  field_conf.options = get_fkey_select_options(gobj, field_desc);
6807
6807
  break;
6808
6808
  case "image":
6809
+ case "icon":
6809
6810
  case "string":
6810
6811
  field_conf.tag = "input";
6811
6812
  field_conf.inputType = "text";
@@ -7723,6 +7724,7 @@ function template2columns(gobj, columns, template, sub_elements) {
7723
7724
  case "hook": break;
7724
7725
  case "fkey": break;
7725
7726
  case "image":
7727
+ case "icon":
7726
7728
  case "string":
7727
7729
  column.editor = "input";
7728
7730
  column.editorParams = {
@@ -8161,6 +8163,7 @@ function treedb_value_2_form_value(gobj, field_desc, value) {
8161
8163
  case "date":
8162
8164
  case "color":
8163
8165
  case "image":
8166
+ case "icon":
8164
8167
  case "tel":
8165
8168
  case "template":
8166
8169
  case "table":
@@ -8253,6 +8256,7 @@ function form_value_2_treedb_value(gobj, field_desc, value) {
8253
8256
  case "date":
8254
8257
  case "color":
8255
8258
  case "image":
8259
+ case "icon":
8256
8260
  case "tel": break;
8257
8261
  case "template":
8258
8262
  if (is_string(value)) try {
@@ -22653,6 +22657,182 @@ function yui_table_filter_clear(table) {
22653
22657
  });
22654
22658
  }
22655
22659
  //#endregion
22660
+ //#region src/lib_icons.js
22661
+ /*********************************************************
22662
+ * lib_icons.js
22663
+ *
22664
+ * Two icon systems are managed here:
22665
+ *
22666
+ * 1. FA-style CSS icons (yui_icons.css)
22667
+ * Usage: <i class="yi-save"></i>
22668
+ * Color: inherits currentColor from parent via CSS mask.
22669
+ *
22670
+ * 2. SVG symbol icons for G6 toolbar (and any other component
22671
+ * that uses <use xlink:href="#id">).
22672
+ * Symbols are injected once into the DOM.
22673
+ * All symbol ids are prefixed with "g6-icon-" to avoid
22674
+ * conflicts with other DOM elements.
22675
+ * Icon paths come from:
22676
+ * fontawesome-free-7.1.0-web/sprites/solid.svg
22677
+ *
22678
+ * G6 toolbar items are managed via CSS class names (className
22679
+ * field in getItems()) using YuiToolbar in c_g6_nodes_tree.js.
22680
+ * This lets lib_graph.js state functions (set_submit_state,
22681
+ * disableElements, …) work on toolbar icons exactly like on
22682
+ * regular Bulma/FA buttons — no icon-specific helpers needed.
22683
+ *
22684
+ * Copyright (c) 2025-2026, ArtGins.
22685
+ * All Rights Reserved.
22686
+ *********************************************************/
22687
+ var CUSTOM_SVG_ICONS_ID = "g6-custom-svgicons";
22688
+ var ICONS = `<svg xmlns="http://www.w3.org/2000/svg">
22689
+ <!-- magnifying-glass-plus -->
22690
+ <symbol id="g6-icon-zoom-in" viewBox="0 0 512 512">
22691
+ <path fill="currentColor" d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376C296.3 401.1 253.9 416 208 416 93.1 416 0 322.9 0 208S93.1 0 208 0 416 93.1 416 208zM208 112c-13.3 0-24 10.7-24 24l0 48-48 0c-13.3 0-24 10.7-24 24s10.7 24 24 24l48 0 0 48c0 13.3 10.7 24 24 24s24-10.7 24-24l0-48 48 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-48 0 0-48c0-13.3-10.7-24-24-24z"/>
22692
+ </symbol>
22693
+ <!-- magnifying-glass-minus -->
22694
+ <symbol id="g6-icon-zoom-out" viewBox="0 0 512 512">
22695
+ <path fill="currentColor" d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376C296.3 401.1 253.9 416 208 416 93.1 416 0 322.9 0 208S93.1 0 208 0 416 93.1 416 208zM136 184c-13.3 0-24 10.7-24 24s10.7 24 24 24l144 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-144 0z"/>
22696
+ </symbol>
22697
+ <!-- house (reset zoom: back to original 100% view) -->
22698
+ <symbol id="g6-icon-home" viewBox="0 0 512 512">
22699
+ <path fill="currentColor" d="M277.8 8.6c-12.3-11.4-31.3-11.4-43.5 0l-224 208c-9.6 9-12.8 22.9-8 35.1S18.8 272 32 272l16 0 0 176c0 35.3 28.7 64 64 64l288 0c35.3 0 64-28.7 64-64l0-176 16 0c13.2 0 25-8.1 29.8-20.3s1.6-26.2-8-35.1l-224-208zM240 320l32 0c26.5 0 48 21.5 48 48l0 96-128 0 0-96c0-26.5 21.5-48 48-48z"/>
22700
+ </symbol>
22701
+ <!-- expand (zoom to fit) -->
22702
+ <symbol id="g6-icon-fit" viewBox="0 0 448 512">
22703
+ <path fill="currentColor" d="M32 32C14.3 32 0 46.3 0 64l0 96c0 17.7 14.3 32 32 32s32-14.3 32-32l0-64 64 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L32 32zM64 352c0-17.7-14.3-32-32-32S0 334.3 0 352l0 96c0 17.7 14.3 32 32 32l96 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-64 0 0-64zM320 32c-17.7 0-32 14.3-32 32s14.3 32 32 32l64 0 0 64c0 17.7 14.3 32 32 32s32-14.3 32-32l0-96c0-17.7-14.3-32-32-32l-96 0zM448 352c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 64-64 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l96 0c17.7 0 32-14.3 32-32l0-96z"/>
22704
+ </symbol>
22705
+ <!-- fit to selection: the same corner brackets as the fit icon,
22706
+ around a marked object. The two sit side by side in the
22707
+ toolbar and have to read as a family, which a borrowed glyph
22708
+ would not. (No backticks in here: the sprite lives inside a
22709
+ template literal.) -->
22710
+ <symbol id="g6-icon-fit-selection" viewBox="0 0 448 512">
22711
+ <path fill="currentColor" d="M32 32C14.3 32 0 46.3 0 64l0 96c0 17.7 14.3 32 32 32s32-14.3 32-32l0-64 64 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L32 32zM64 352c0-17.7-14.3-32-32-32S0 334.3 0 352l0 96c0 17.7 14.3 32 32 32l96 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-64 0 0-64zM320 32c-17.7 0-32 14.3-32 32s14.3 32 32 32l64 0 0 64c0 17.7 14.3 32 32 32s32-14.3 32-32l0-96c0-17.7-14.3-32-32-32l-96 0zM448 352c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 64-64 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l96 0c17.7 0 32-14.3 32-32l0-96z"/>
22712
+ <rect fill="currentColor" x="144" y="176" width="160" height="160" rx="24"/>
22713
+ </symbol>
22714
+ <!-- crosshairs (center) -->
22715
+ <symbol id="g6-icon-center" viewBox="0 0 576 512">
22716
+ <path fill="currentColor" d="M288-16c17.7 0 32 14.3 32 32l0 18.3c98.1 14 175.7 91.6 189.7 189.7l18.3 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-18.3 0c-14 98.1-91.6 175.7-189.7 189.7l0 18.3c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-18.3C157.9 463.7 80.3 386.1 66.3 288L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l18.3 0C80.3 125.9 157.9 48.3 256 34.3L256 16c0-17.7 14.3-32 32-32zM131.2 288c12.7 62.7 62.1 112.1 124.8 124.8l0-12.8c0-17.7 14.3-32 32-32s32 14.3 32 32l0 12.8c62.7-12.7 112.1-62.1 124.8-124.8L432 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l12.8 0C432.1 161.3 382.7 111.9 320 99.2l0 12.8c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-12.8C193.3 111.9 143.9 161.3 131.2 224l12.8 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-12.8 0zM288 208a48 48 0 1 1 0 96 48 48 0 1 1 0-96z"/>
22717
+ </symbol>
22718
+ <!-- up-right-and-down-left-from-center (enter fullscreen) -->
22719
+ <symbol id="g6-icon-fullscreen" viewBox="0 0 512 512">
22720
+ <path fill="currentColor" d="M344 0L488 0c13.3 0 24 10.7 24 24l0 144c0 9.7-5.8 18.5-14.8 22.2s-19.3 1.7-26.2-5.2l-39-39-87 87c-9.4 9.4-24.6 9.4-33.9 0l-32-32c-9.4-9.4-9.4-24.6 0-33.9l87-87-39-39c-6.9-6.9-8.9-17.2-5.2-26.2S334.3 0 344 0zM168 512L24 512c-13.3 0-24-10.7-24-24L0 344c0-9.7 5.8-18.5 14.8-22.2S34.1 320.2 41 327l39 39 87-87c9.4-9.4 24.6-9.4 33.9 0l32 32c9.4 9.4 9.4 24.6 0 33.9l-87 87 39 39c6.9 6.9 8.9 17.2 5.2 26.2S177.7 512 168 512z"/>
22721
+ </symbol>
22722
+ <!-- down-left-and-up-right-to-center (exit fullscreen) -->
22723
+ <symbol id="g6-icon-fullscreen-exit" viewBox="0 0 512 512">
22724
+ <path fill="currentColor" d="M439.5 7c9.4-9.4 24.6-9.4 33.9 0l32 32c9.4 9.4 9.4 24.6 0 33.9l-87 87 39 39c6.9 6.9 8.9 17.2 5.2 26.2S450.2 240 440.5 240l-144 0c-13.3 0-24-10.7-24-24l0-144c0-9.7 5.8-18.5 14.8-22.2s19.3-1.7 26.2 5.2l39 39 87-87zM72.5 272l144 0c13.3 0 24 10.7 24 24l0 144c0 9.7-5.8 18.5-14.8 22.2s-19.3 1.7-26.2-5.2l-39-39-87 87c-9.4 9.4-24.6 9.4-33.9 0l-32-32c-9.4-9.4-9.4-24.6 0-33.9l87-87-39-39c-6.9-6.9-8.9-17.2-5.2-26.2S62.8 272 72.5 272z"/>
22725
+ </symbol>
22726
+ <!-- arrow-rotate-left (undo) -->
22727
+ <symbol id="g6-icon-undo" viewBox="0 0 512 512">
22728
+ <path fill="currentColor" d="M256 64c-56.8 0-107.9 24.7-143.1 64l47.1 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 192c-17.7 0-32-14.3-32-32L0 32C0 14.3 14.3 0 32 0S64 14.3 64 32l0 54.7C110.9 33.6 179.5 0 256 0 397.4 0 512 114.6 512 256S397.4 512 256 512c-87 0-163.9-43.4-210.1-109.7-10.1-14.5-6.6-34.4 7.9-44.6s34.4-6.6 44.6 7.9c34.8 49.8 92.4 82.3 157.6 82.3 106 0 192-86 192-192S362 64 256 64z"/>
22729
+ </symbol>
22730
+ <!-- arrow-rotate-right (redo) -->
22731
+ <symbol id="g6-icon-redo" viewBox="0 0 512 512">
22732
+ <path fill="currentColor" d="M436.7 74.7L448 85.4 448 32c0-17.7 14.3-32 32-32s32 14.3 32 32l0 128c0 17.7-14.3 32-32 32l-128 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l47.9 0-7.6-7.2c-.2-.2-.4-.4-.6-.6-75-75-196.5-75-271.5 0s-75 196.5 0 271.5 196.5 75 271.5 0c8.2-8.2 15.5-16.9 21.9-26.1 10.1-14.5 30.1-18 44.6-7.9s18 30.1 7.9 44.6c-8.5 12.2-18.2 23.8-29.1 34.7-100 100-262.1 100-362 0S-25 175 75 75c99.9-99.9 261.7-100 361.7-.3z"/>
22733
+ </symbol>
22734
+ <!-- pen (edit node) -->
22735
+ <symbol id="g6-icon-edit" viewBox="0 0 512 512">
22736
+ <path fill="currentColor" d="M352.9 21.2L308 66.1 445.9 204 490.8 159.1C504.4 145.6 512 127.2 512 108s-7.6-37.6-21.2-51.1L455.1 21.2C441.6 7.6 423.2 0 404 0s-37.6 7.6-51.1 21.2zM274.1 100L58.9 315.1c-10.7 10.7-18.5 24.1-22.6 38.7L.9 481.6c-2.3 8.3 0 17.3 6.2 23.4s15.1 8.5 23.4 6.2l127.8-35.5c14.6-4.1 27.9-11.8 38.7-22.6L412 237.9 274.1 100z"/>
22737
+ </symbol>
22738
+ <!-- trash-can (delete) -->
22739
+ <symbol id="g6-icon-delete" viewBox="0 0 448 512">
22740
+ <path fill="currentColor" d="M136.7 5.9C141.1-7.2 153.3-16 167.1-16l113.9 0c13.8 0 26 8.8 30.4 21.9L320 32 416 32c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 96C14.3 96 0 81.7 0 64S14.3 32 32 32l96 0 8.7-26.1zM32 144l384 0 0 304c0 35.3-28.7 64-64 64L96 512c-35.3 0-64-28.7-64-64l0-304zm88 64c-13.3 0-24 10.7-24 24l0 192c0 13.3 10.7 24 24 24s24-10.7 24-24l0-192c0-13.3-10.7-24-24-24zm104 0c-13.3 0-24 10.7-24 24l0 192c0 13.3 10.7 24 24 24s24-10.7 24-24l0-192c0-13.3-10.7-24-24-24zm104 0c-13.3 0-24 10.7-24 24l0 192c0 13.3 10.7 24 24 24s24-10.7 24-24l0-192c0-13.3-10.7-24-24-24z"/>
22741
+ </symbol>
22742
+ <!-- link (link nodes) -->
22743
+ <symbol id="g6-icon-link" viewBox="0 0 576 512">
22744
+ <path fill="currentColor" d="M419.5 96c-16.6 0-32.7 4.5-46.8 12.7-15.8-16-34.2-29.4-54.5-39.5 28.2-24 64.1-37.2 101.3-37.2 86.4 0 156.5 70 156.5 156.5 0 41.5-16.5 81.3-45.8 110.6l-71.1 71.1c-29.3 29.3-69.1 45.8-110.6 45.8-86.4 0-156.5-70-156.5-156.5 0-1.5 0-3 .1-4.5 .5-17.7 15.2-31.6 32.9-31.1s31.6 15.2 31.1 32.9c0 .9 0 1.8 0 2.6 0 51.1 41.4 92.5 92.5 92.5 24.5 0 48-9.7 65.4-27.1l71.1-71.1c17.3-17.3 27.1-40.9 27.1-65.4 0-51.1-41.4-92.5-92.5-92.5zM275.2 173.3c-1.9-.8-3.8-1.9-5.5-3.1-12.6-6.5-27-10.2-42.1-10.2-24.5 0-48 9.7-65.4 27.1L91.1 258.2c-17.3 17.3-27.1 40.9-27.1 65.4 0 51.1 41.4 92.5 92.5 92.5 16.5 0 32.6-4.4 46.7-12.6 15.8 16 34.2 29.4 54.6 39.5-28.2 23.9-64 37.2-101.3 37.2-86.4 0-156.5-70-156.5-156.5 0-41.5 16.5-81.3 45.8-110.6l71.1-71.1c29.3-29.3 69.1-45.8 110.6-45.8 86.6 0 156.5 70.6 156.5 156.9 0 1.3 0 2.6 0 3.9-.4 17.7-15.1 31.6-32.8 31.2s-31.6-15.1-31.2-32.8c0-.8 0-1.5 0-2.3 0-33.7-18-63.3-44.8-79.6z"/>
22745
+ </symbol>
22746
+ <!-- link-slash (unlink) -->
22747
+ <symbol id="g6-icon-unlink" viewBox="0 0 576 512">
22748
+ <path fill="currentColor" d="M41-24.9c-9.4-9.4-24.6-9.4-33.9 0S-2.3-.3 7 9.1l528 528c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-122-122c4.2-3.4 8.3-7.1 12.1-10.9l71.1-71.1c29.3-29.3 45.8-69.1 45.8-110.6 0-86.4-70-156.5-156.5-156.5-37.3 0-73.1 13.3-101.3 37.2 20.3 10.1 38.7 23.5 54.5 39.5 14.1-8.3 30.2-12.7 46.8-12.7 51.1 0 92.5 41.4 92.5 92.5 0 24.5-9.7 48-27.1 65.4l-71.1 71.1c-3.9 3.9-8.1 7.4-12.6 10.5l-47.5-47.5c16.5-.9 29.7-14.4 30.2-31.1 0-1.3 0-2.6 0-3.9 0-86.3-69.9-156.9-156.5-156.9-19.2 0-37.9 3.5-55.5 10.2L41-24.9zM225.9 160c.6 0 1.1 0 1.7 0 15.1 0 29.5 3.7 42.1 10.2 1.8 1.2 3.6 2.3 5.5 3.1 26.8 16.3 44.8 45.9 44.8 79.6 0 .4 0 .8 0 1.2L225.9 160zM346.2 416L192 261.8c1.2 84.6 69.6 152.9 154.1 154.1zM139.7 209.5l-45.3-45.3-48.6 48.6c-29.3 29.3-45.8 69.1-45.8 110.6 0 86.4 70 156.5 156.5 156.5 37.2 0 73.1-13.3 101.3-37.2-20.3-10.1-38.8-23.5-54.6-39.5-14 8.2-30.1 12.6-46.7 12.6-51.1 0-92.5-41.4-92.5-92.5 0-24.5 9.7-48 27.1-65.4l48.6-48.6z"/>
22749
+ </symbol>
22750
+ <!-- play (run node) -->
22751
+ <symbol id="g6-icon-run" viewBox="0 0 448 512">
22752
+ <path fill="currentColor" d="M91.2 36.9c-12.4-6.8-27.4-6.5-39.6 .7S32 57.9 32 72l0 368c0 14.1 7.5 27.2 19.6 34.4s27.2 7.5 39.6 .7l336-184c12.8-7 20.8-20.5 20.8-35.1s-8-28.1-20.8-35.1l-336-184z"/>
22753
+ </symbol>
22754
+ <!-- clone (copy size to other nodes/ports) -->
22755
+ <symbol id="g6-icon-resize" viewBox="0 0 512 512">
22756
+ <path fill="currentColor" d="M288 448l-224 0 0-224 48 0 0-64-48 0c-35.3 0-64 28.7-64 64L0 448c0 35.3 28.7 64 64 64l224 0c35.3 0 64-28.7 64-64l0-48-64 0 0 48zm-64-96l224 0c35.3 0 64-28.7 64-64l0-224c0-35.3-28.7-64-64-64L224 0c-35.3 0-64 28.7-64 64l0 224c0 35.3 28.7 64 64 64z"/>
22757
+ </symbol>
22758
+ <!-- plus (create node). Deliberately NOT the FA7 solid plus:
22759
+ its arms are ~14% of the width and read thin next to the
22760
+ other solid glyphs. Bold geometric plus (~23% arm
22761
+ thickness) with long arms (32..480) so it reads as a "+",
22762
+ not a stubby Red-Cross square. -->
22763
+ <symbol id="g6-icon-plus" viewBox="0 0 512 512">
22764
+ <path fill="currentColor" d="M316 32 L316 196 L480 196 L480 316 L316 316 L316 480 L196 480 L196 316 L32 316 L32 196 L196 196 L196 32 Z"/>
22765
+ </symbol>
22766
+ <!-- ellipsis-vertical (unfold the floating toolbar).
22767
+ The strip it stands for is a vertical stack, and a vertical
22768
+ ellipsis is what "there is more of this here" is drawn as
22769
+ everywhere else. -->
22770
+ <symbol id="g6-icon-toolbar-show" viewBox="0 0 128 512">
22771
+ <path fill="currentColor" d="M64 360a56 56 0 1 0 0 112 56 56 0 1 0 0-112zm0-160a56 56 0 1 0 0 112 56 56 0 1 0 0-112zM120 96A56 56 0 1 0 8 96a56 56 0 1 0 112 0z"/>
22772
+ </symbol>
22773
+ <!-- xmark (fold the floating toolbar away).
22774
+ Not a chevron: the two toolbars sit on OPPOSITE edges, so a
22775
+ direction would point the wrong way on one of them. What the
22776
+ button does is close an overlay, and that is an x. -->
22777
+ <symbol id="g6-icon-toolbar-hide" viewBox="0 0 384 512">
22778
+ <path fill="currentColor" d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"/>
22779
+ </symbol>
22780
+ <!-- dashed marquee (selection mode).
22781
+ The band ITSELF, because that is what the button turns on: a
22782
+ drag on the canvas draws one and a tap picks a card. Not the
22783
+ fit-to-selection glyph next to it in the other toolbar -- that
22784
+ one is solid brackets around a solid object and means "put the
22785
+ camera on what is picked", which is the opposite end of the
22786
+ gesture. Dashes: 16 segments of 59 with gaps of 36 over a
22787
+ perimeter of 1520, so they land on the corners. -->
22788
+ <symbol id="g6-icon-select-mode" viewBox="0 0 512 512">
22789
+ <rect x="46" y="86" width="420" height="340" fill="none"
22790
+ stroke="currentColor" stroke-width="40"
22791
+ stroke-dasharray="59 36"/>
22792
+ </symbol>
22793
+ <!-- location-crosshairs (anchor the camera on one element).
22794
+ The SAME path as the DOM toolbars and their yi-location-crosshairs
22795
+ mask: the two toolbars sit in one console, and a control that
22796
+ does one thing has to be drawn one way. -->
22797
+ <symbol id="g6-icon-anchor" viewBox="0 0 576 512">
22798
+ <path fill="currentColor" d="M288-16c17.7 0 32 14.3 32 32l0 18.3c98.1 14 175.7 91.6 189.7 189.7l18.3 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-18.3 0c-14 98.1-91.6 175.7-189.7 189.7l0 18.3c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-18.3C157.9 463.7 80.3 386.1 66.3 288L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l18.3 0C80.3 125.9 157.9 48.3 256 34.3L256 16c0-17.7 14.3-32 32-32zM128 256a160 160 0 1 0 320 0 160 160 0 1 0 -320 0zm160-96a96 96 0 1 1 0 192 96 96 0 1 1 0-192z"/>
22799
+ </symbol>
22800
+ <!-- floppy-disk (save) -->
22801
+ <symbol id="g6-icon-save" viewBox="0 0 448 512">
22802
+ <path fill="currentColor" d="M64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l320 0c35.3 0 64-28.7 64-64l0-242.7c0-17-6.7-33.3-18.7-45.3L352 50.7C340 38.7 323.7 32 306.7 32L64 32zm32 96c0-17.7 14.3-32 32-32l160 0c17.7 0 32 14.3 32 32l0 64c0 17.7-14.3 32-32 32l-160 0c-17.7 0-32-14.3-32-32l0-64zM224 288a64 64 0 1 1 0 128 64 64 0 1 1 0-128z"/>
22803
+ </symbol>
22804
+ </svg>`;
22805
+ function inject_svg_icons() {
22806
+ if (document.getElementById(CUSTOM_SVG_ICONS_ID)) return;
22807
+ const div = document.createElement("div");
22808
+ div.id = CUSTOM_SVG_ICONS_ID;
22809
+ div.style.display = "none";
22810
+ div.innerHTML = ICONS;
22811
+ document.body.appendChild(div);
22812
+ }
22813
+ var __icon_defined__ = {};
22814
+ function yui_icon_is_defined(name) {
22815
+ if (!name || typeof name !== "string") return false;
22816
+ if (__icon_defined__[name] !== void 0) return __icon_defined__[name];
22817
+ let defined = false;
22818
+ try {
22819
+ const el = document.createElement("i");
22820
+ el.className = name;
22821
+ el.style.position = "absolute";
22822
+ el.style.visibility = "hidden";
22823
+ el.style.pointerEvents = "none";
22824
+ document.body.appendChild(el);
22825
+ const st = window.getComputedStyle(el, "::before");
22826
+ const mask = st.maskImage || st.webkitMaskImage || "";
22827
+ defined = !!mask && mask !== "none";
22828
+ document.body.removeChild(el);
22829
+ } catch (e) {
22830
+ defined = false;
22831
+ }
22832
+ __icon_defined__[name] = defined;
22833
+ return defined;
22834
+ }
22835
+ //#endregion
22656
22836
  //#region src/yui_row_search.js
22657
22837
  /***********************************************************************
22658
22838
  * yui_row_search.js
@@ -23733,6 +23913,11 @@ function create_tabulator(gobj) {
23733
23913
  hozAlign = "center";
23734
23914
  colFormatter = "color";
23735
23915
  break;
23916
+ case "icon":
23917
+ hozAlign = "center";
23918
+ vertAlign = "middle";
23919
+ colFormatter = icon_formatter;
23920
+ break;
23736
23921
  case "object":
23737
23922
  case "dict":
23738
23923
  case "template":
@@ -23956,6 +24141,39 @@ function table__destroy(gobj) {
23956
24141
  }
23957
24142
  }
23958
24143
  /************************************************************
24144
+ * Cell of a col flagged `icon`: the value is the NAME of an
24145
+ * icon of the app's set ("yi-bolt"), so it is DRAWN.
24146
+ *
24147
+ * Built as a DOM node and not as an HTML string: the value is
24148
+ * raw record data and must never be parsed as markup -- and
24149
+ * here it also becomes a CSS class, so it is filtered to the
24150
+ * shape of a class name before it gets near one.
24151
+ *
24152
+ * A name the set does not carry falls back to the TEXT of it.
24153
+ * The catch-all rule `[class^="yi-"]::before` paints a
24154
+ * currentColor box for any name, so drawing it anyway would
24155
+ * render a solid square -- a glyph nobody recognises rather
24156
+ * than a mistake somebody can fix.
24157
+ ************************************************************/
24158
+ function icon_formatter(cell) {
24159
+ let name = cell.getValue();
24160
+ if (!is_string(name) || empty_string(name)) return "";
24161
+ name = name.trim();
24162
+ if (!/^[a-z0-9-]+$/.test(name) || !yui_icon_is_defined(name)) return createElement2([
24163
+ "span",
24164
+ {
24165
+ class: "ICON_CELL_UNKNOWN is-size-7 has-text-grey",
24166
+ title: name
24167
+ },
24168
+ name
24169
+ ]);
24170
+ return createElement2(["span", {
24171
+ class: `ICON_CELL ${name}`,
24172
+ title: name,
24173
+ "aria-label": name
24174
+ }]);
24175
+ }
24176
+ /************************************************************
23959
24177
  * Cell of a col holding a JSON document (dict/list/blob/
23960
24178
  * template/coordinates/…): a one-line truncated preview,
23961
24179
  * marked as a link because the click opens the whole value
@@ -24067,6 +24285,7 @@ function transform__treedb_value_2_table_value(gobj, col, value, row, field) {
24067
24285
  }
24068
24286
  break;
24069
24287
  case "color": break;
24288
+ case "icon": break;
24070
24289
  case "image": break;
24071
24290
  default: log_error(`transform__treedb_value_2_table_value() unhandled type '${field_desc.type}' (real_type='${field_desc.real_type}') for field '${field}', topic ${priv.topic_name}`);
24072
24291
  }
@@ -52400,160 +52619,6 @@ Sector.PARSED_STYLE_LIST = new Set([].concat(_toConsumableArray(Path.PARSED_STYL
52400
52619
  "endAngle"
52401
52620
  ]));
52402
52621
  //#endregion
52403
- //#region src/lib_icons.js
52404
- /*********************************************************
52405
- * lib_icons.js
52406
- *
52407
- * Two icon systems are managed here:
52408
- *
52409
- * 1. FA-style CSS icons (yui_icons.css)
52410
- * Usage: <i class="yi-save"></i>
52411
- * Color: inherits currentColor from parent via CSS mask.
52412
- *
52413
- * 2. SVG symbol icons for G6 toolbar (and any other component
52414
- * that uses <use xlink:href="#id">).
52415
- * Symbols are injected once into the DOM.
52416
- * All symbol ids are prefixed with "g6-icon-" to avoid
52417
- * conflicts with other DOM elements.
52418
- * Icon paths come from:
52419
- * fontawesome-free-7.1.0-web/sprites/solid.svg
52420
- *
52421
- * G6 toolbar items are managed via CSS class names (className
52422
- * field in getItems()) using YuiToolbar in c_g6_nodes_tree.js.
52423
- * This lets lib_graph.js state functions (set_submit_state,
52424
- * disableElements, …) work on toolbar icons exactly like on
52425
- * regular Bulma/FA buttons — no icon-specific helpers needed.
52426
- *
52427
- * Copyright (c) 2025-2026, ArtGins.
52428
- * All Rights Reserved.
52429
- *********************************************************/
52430
- var CUSTOM_SVG_ICONS_ID = "g6-custom-svgicons";
52431
- var ICONS = `<svg xmlns="http://www.w3.org/2000/svg">
52432
- <!-- magnifying-glass-plus -->
52433
- <symbol id="g6-icon-zoom-in" viewBox="0 0 512 512">
52434
- <path fill="currentColor" d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376C296.3 401.1 253.9 416 208 416 93.1 416 0 322.9 0 208S93.1 0 208 0 416 93.1 416 208zM208 112c-13.3 0-24 10.7-24 24l0 48-48 0c-13.3 0-24 10.7-24 24s10.7 24 24 24l48 0 0 48c0 13.3 10.7 24 24 24s24-10.7 24-24l0-48 48 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-48 0 0-48c0-13.3-10.7-24-24-24z"/>
52435
- </symbol>
52436
- <!-- magnifying-glass-minus -->
52437
- <symbol id="g6-icon-zoom-out" viewBox="0 0 512 512">
52438
- <path fill="currentColor" d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376C296.3 401.1 253.9 416 208 416 93.1 416 0 322.9 0 208S93.1 0 208 0 416 93.1 416 208zM136 184c-13.3 0-24 10.7-24 24s10.7 24 24 24l144 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-144 0z"/>
52439
- </symbol>
52440
- <!-- house (reset zoom: back to original 100% view) -->
52441
- <symbol id="g6-icon-home" viewBox="0 0 512 512">
52442
- <path fill="currentColor" d="M277.8 8.6c-12.3-11.4-31.3-11.4-43.5 0l-224 208c-9.6 9-12.8 22.9-8 35.1S18.8 272 32 272l16 0 0 176c0 35.3 28.7 64 64 64l288 0c35.3 0 64-28.7 64-64l0-176 16 0c13.2 0 25-8.1 29.8-20.3s1.6-26.2-8-35.1l-224-208zM240 320l32 0c26.5 0 48 21.5 48 48l0 96-128 0 0-96c0-26.5 21.5-48 48-48z"/>
52443
- </symbol>
52444
- <!-- expand (zoom to fit) -->
52445
- <symbol id="g6-icon-fit" viewBox="0 0 448 512">
52446
- <path fill="currentColor" d="M32 32C14.3 32 0 46.3 0 64l0 96c0 17.7 14.3 32 32 32s32-14.3 32-32l0-64 64 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L32 32zM64 352c0-17.7-14.3-32-32-32S0 334.3 0 352l0 96c0 17.7 14.3 32 32 32l96 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-64 0 0-64zM320 32c-17.7 0-32 14.3-32 32s14.3 32 32 32l64 0 0 64c0 17.7 14.3 32 32 32s32-14.3 32-32l0-96c0-17.7-14.3-32-32-32l-96 0zM448 352c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 64-64 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l96 0c17.7 0 32-14.3 32-32l0-96z"/>
52447
- </symbol>
52448
- <!-- fit to selection: the same corner brackets as the fit icon,
52449
- around a marked object. The two sit side by side in the
52450
- toolbar and have to read as a family, which a borrowed glyph
52451
- would not. (No backticks in here: the sprite lives inside a
52452
- template literal.) -->
52453
- <symbol id="g6-icon-fit-selection" viewBox="0 0 448 512">
52454
- <path fill="currentColor" d="M32 32C14.3 32 0 46.3 0 64l0 96c0 17.7 14.3 32 32 32s32-14.3 32-32l0-64 64 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L32 32zM64 352c0-17.7-14.3-32-32-32S0 334.3 0 352l0 96c0 17.7 14.3 32 32 32l96 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-64 0 0-64zM320 32c-17.7 0-32 14.3-32 32s14.3 32 32 32l64 0 0 64c0 17.7 14.3 32 32 32s32-14.3 32-32l0-96c0-17.7-14.3-32-32-32l-96 0zM448 352c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 64-64 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l96 0c17.7 0 32-14.3 32-32l0-96z"/>
52455
- <rect fill="currentColor" x="144" y="176" width="160" height="160" rx="24"/>
52456
- </symbol>
52457
- <!-- crosshairs (center) -->
52458
- <symbol id="g6-icon-center" viewBox="0 0 576 512">
52459
- <path fill="currentColor" d="M288-16c17.7 0 32 14.3 32 32l0 18.3c98.1 14 175.7 91.6 189.7 189.7l18.3 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-18.3 0c-14 98.1-91.6 175.7-189.7 189.7l0 18.3c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-18.3C157.9 463.7 80.3 386.1 66.3 288L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l18.3 0C80.3 125.9 157.9 48.3 256 34.3L256 16c0-17.7 14.3-32 32-32zM131.2 288c12.7 62.7 62.1 112.1 124.8 124.8l0-12.8c0-17.7 14.3-32 32-32s32 14.3 32 32l0 12.8c62.7-12.7 112.1-62.1 124.8-124.8L432 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l12.8 0C432.1 161.3 382.7 111.9 320 99.2l0 12.8c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-12.8C193.3 111.9 143.9 161.3 131.2 224l12.8 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-12.8 0zM288 208a48 48 0 1 1 0 96 48 48 0 1 1 0-96z"/>
52460
- </symbol>
52461
- <!-- up-right-and-down-left-from-center (enter fullscreen) -->
52462
- <symbol id="g6-icon-fullscreen" viewBox="0 0 512 512">
52463
- <path fill="currentColor" d="M344 0L488 0c13.3 0 24 10.7 24 24l0 144c0 9.7-5.8 18.5-14.8 22.2s-19.3 1.7-26.2-5.2l-39-39-87 87c-9.4 9.4-24.6 9.4-33.9 0l-32-32c-9.4-9.4-9.4-24.6 0-33.9l87-87-39-39c-6.9-6.9-8.9-17.2-5.2-26.2S334.3 0 344 0zM168 512L24 512c-13.3 0-24-10.7-24-24L0 344c0-9.7 5.8-18.5 14.8-22.2S34.1 320.2 41 327l39 39 87-87c9.4-9.4 24.6-9.4 33.9 0l32 32c9.4 9.4 9.4 24.6 0 33.9l-87 87 39 39c6.9 6.9 8.9 17.2 5.2 26.2S177.7 512 168 512z"/>
52464
- </symbol>
52465
- <!-- down-left-and-up-right-to-center (exit fullscreen) -->
52466
- <symbol id="g6-icon-fullscreen-exit" viewBox="0 0 512 512">
52467
- <path fill="currentColor" d="M439.5 7c9.4-9.4 24.6-9.4 33.9 0l32 32c9.4 9.4 9.4 24.6 0 33.9l-87 87 39 39c6.9 6.9 8.9 17.2 5.2 26.2S450.2 240 440.5 240l-144 0c-13.3 0-24-10.7-24-24l0-144c0-9.7 5.8-18.5 14.8-22.2s19.3-1.7 26.2 5.2l39 39 87-87zM72.5 272l144 0c13.3 0 24 10.7 24 24l0 144c0 9.7-5.8 18.5-14.8 22.2s-19.3 1.7-26.2-5.2l-39-39-87 87c-9.4 9.4-24.6 9.4-33.9 0l-32-32c-9.4-9.4-9.4-24.6 0-33.9l87-87-39-39c-6.9-6.9-8.9-17.2-5.2-26.2S62.8 272 72.5 272z"/>
52468
- </symbol>
52469
- <!-- arrow-rotate-left (undo) -->
52470
- <symbol id="g6-icon-undo" viewBox="0 0 512 512">
52471
- <path fill="currentColor" d="M256 64c-56.8 0-107.9 24.7-143.1 64l47.1 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 192c-17.7 0-32-14.3-32-32L0 32C0 14.3 14.3 0 32 0S64 14.3 64 32l0 54.7C110.9 33.6 179.5 0 256 0 397.4 0 512 114.6 512 256S397.4 512 256 512c-87 0-163.9-43.4-210.1-109.7-10.1-14.5-6.6-34.4 7.9-44.6s34.4-6.6 44.6 7.9c34.8 49.8 92.4 82.3 157.6 82.3 106 0 192-86 192-192S362 64 256 64z"/>
52472
- </symbol>
52473
- <!-- arrow-rotate-right (redo) -->
52474
- <symbol id="g6-icon-redo" viewBox="0 0 512 512">
52475
- <path fill="currentColor" d="M436.7 74.7L448 85.4 448 32c0-17.7 14.3-32 32-32s32 14.3 32 32l0 128c0 17.7-14.3 32-32 32l-128 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l47.9 0-7.6-7.2c-.2-.2-.4-.4-.6-.6-75-75-196.5-75-271.5 0s-75 196.5 0 271.5 196.5 75 271.5 0c8.2-8.2 15.5-16.9 21.9-26.1 10.1-14.5 30.1-18 44.6-7.9s18 30.1 7.9 44.6c-8.5 12.2-18.2 23.8-29.1 34.7-100 100-262.1 100-362 0S-25 175 75 75c99.9-99.9 261.7-100 361.7-.3z"/>
52476
- </symbol>
52477
- <!-- pen (edit node) -->
52478
- <symbol id="g6-icon-edit" viewBox="0 0 512 512">
52479
- <path fill="currentColor" d="M352.9 21.2L308 66.1 445.9 204 490.8 159.1C504.4 145.6 512 127.2 512 108s-7.6-37.6-21.2-51.1L455.1 21.2C441.6 7.6 423.2 0 404 0s-37.6 7.6-51.1 21.2zM274.1 100L58.9 315.1c-10.7 10.7-18.5 24.1-22.6 38.7L.9 481.6c-2.3 8.3 0 17.3 6.2 23.4s15.1 8.5 23.4 6.2l127.8-35.5c14.6-4.1 27.9-11.8 38.7-22.6L412 237.9 274.1 100z"/>
52480
- </symbol>
52481
- <!-- trash-can (delete) -->
52482
- <symbol id="g6-icon-delete" viewBox="0 0 448 512">
52483
- <path fill="currentColor" d="M136.7 5.9C141.1-7.2 153.3-16 167.1-16l113.9 0c13.8 0 26 8.8 30.4 21.9L320 32 416 32c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 96C14.3 96 0 81.7 0 64S14.3 32 32 32l96 0 8.7-26.1zM32 144l384 0 0 304c0 35.3-28.7 64-64 64L96 512c-35.3 0-64-28.7-64-64l0-304zm88 64c-13.3 0-24 10.7-24 24l0 192c0 13.3 10.7 24 24 24s24-10.7 24-24l0-192c0-13.3-10.7-24-24-24zm104 0c-13.3 0-24 10.7-24 24l0 192c0 13.3 10.7 24 24 24s24-10.7 24-24l0-192c0-13.3-10.7-24-24-24zm104 0c-13.3 0-24 10.7-24 24l0 192c0 13.3 10.7 24 24 24s24-10.7 24-24l0-192c0-13.3-10.7-24-24-24z"/>
52484
- </symbol>
52485
- <!-- link (link nodes) -->
52486
- <symbol id="g6-icon-link" viewBox="0 0 576 512">
52487
- <path fill="currentColor" d="M419.5 96c-16.6 0-32.7 4.5-46.8 12.7-15.8-16-34.2-29.4-54.5-39.5 28.2-24 64.1-37.2 101.3-37.2 86.4 0 156.5 70 156.5 156.5 0 41.5-16.5 81.3-45.8 110.6l-71.1 71.1c-29.3 29.3-69.1 45.8-110.6 45.8-86.4 0-156.5-70-156.5-156.5 0-1.5 0-3 .1-4.5 .5-17.7 15.2-31.6 32.9-31.1s31.6 15.2 31.1 32.9c0 .9 0 1.8 0 2.6 0 51.1 41.4 92.5 92.5 92.5 24.5 0 48-9.7 65.4-27.1l71.1-71.1c17.3-17.3 27.1-40.9 27.1-65.4 0-51.1-41.4-92.5-92.5-92.5zM275.2 173.3c-1.9-.8-3.8-1.9-5.5-3.1-12.6-6.5-27-10.2-42.1-10.2-24.5 0-48 9.7-65.4 27.1L91.1 258.2c-17.3 17.3-27.1 40.9-27.1 65.4 0 51.1 41.4 92.5 92.5 92.5 16.5 0 32.6-4.4 46.7-12.6 15.8 16 34.2 29.4 54.6 39.5-28.2 23.9-64 37.2-101.3 37.2-86.4 0-156.5-70-156.5-156.5 0-41.5 16.5-81.3 45.8-110.6l71.1-71.1c29.3-29.3 69.1-45.8 110.6-45.8 86.6 0 156.5 70.6 156.5 156.9 0 1.3 0 2.6 0 3.9-.4 17.7-15.1 31.6-32.8 31.2s-31.6-15.1-31.2-32.8c0-.8 0-1.5 0-2.3 0-33.7-18-63.3-44.8-79.6z"/>
52488
- </symbol>
52489
- <!-- link-slash (unlink) -->
52490
- <symbol id="g6-icon-unlink" viewBox="0 0 576 512">
52491
- <path fill="currentColor" d="M41-24.9c-9.4-9.4-24.6-9.4-33.9 0S-2.3-.3 7 9.1l528 528c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-122-122c4.2-3.4 8.3-7.1 12.1-10.9l71.1-71.1c29.3-29.3 45.8-69.1 45.8-110.6 0-86.4-70-156.5-156.5-156.5-37.3 0-73.1 13.3-101.3 37.2 20.3 10.1 38.7 23.5 54.5 39.5 14.1-8.3 30.2-12.7 46.8-12.7 51.1 0 92.5 41.4 92.5 92.5 0 24.5-9.7 48-27.1 65.4l-71.1 71.1c-3.9 3.9-8.1 7.4-12.6 10.5l-47.5-47.5c16.5-.9 29.7-14.4 30.2-31.1 0-1.3 0-2.6 0-3.9 0-86.3-69.9-156.9-156.5-156.9-19.2 0-37.9 3.5-55.5 10.2L41-24.9zM225.9 160c.6 0 1.1 0 1.7 0 15.1 0 29.5 3.7 42.1 10.2 1.8 1.2 3.6 2.3 5.5 3.1 26.8 16.3 44.8 45.9 44.8 79.6 0 .4 0 .8 0 1.2L225.9 160zM346.2 416L192 261.8c1.2 84.6 69.6 152.9 154.1 154.1zM139.7 209.5l-45.3-45.3-48.6 48.6c-29.3 29.3-45.8 69.1-45.8 110.6 0 86.4 70 156.5 156.5 156.5 37.2 0 73.1-13.3 101.3-37.2-20.3-10.1-38.8-23.5-54.6-39.5-14 8.2-30.1 12.6-46.7 12.6-51.1 0-92.5-41.4-92.5-92.5 0-24.5 9.7-48 27.1-65.4l48.6-48.6z"/>
52492
- </symbol>
52493
- <!-- play (run node) -->
52494
- <symbol id="g6-icon-run" viewBox="0 0 448 512">
52495
- <path fill="currentColor" d="M91.2 36.9c-12.4-6.8-27.4-6.5-39.6 .7S32 57.9 32 72l0 368c0 14.1 7.5 27.2 19.6 34.4s27.2 7.5 39.6 .7l336-184c12.8-7 20.8-20.5 20.8-35.1s-8-28.1-20.8-35.1l-336-184z"/>
52496
- </symbol>
52497
- <!-- clone (copy size to other nodes/ports) -->
52498
- <symbol id="g6-icon-resize" viewBox="0 0 512 512">
52499
- <path fill="currentColor" d="M288 448l-224 0 0-224 48 0 0-64-48 0c-35.3 0-64 28.7-64 64L0 448c0 35.3 28.7 64 64 64l224 0c35.3 0 64-28.7 64-64l0-48-64 0 0 48zm-64-96l224 0c35.3 0 64-28.7 64-64l0-224c0-35.3-28.7-64-64-64L224 0c-35.3 0-64 28.7-64 64l0 224c0 35.3 28.7 64 64 64z"/>
52500
- </symbol>
52501
- <!-- plus (create node). Deliberately NOT the FA7 solid plus:
52502
- its arms are ~14% of the width and read thin next to the
52503
- other solid glyphs. Bold geometric plus (~23% arm
52504
- thickness) with long arms (32..480) so it reads as a "+",
52505
- not a stubby Red-Cross square. -->
52506
- <symbol id="g6-icon-plus" viewBox="0 0 512 512">
52507
- <path fill="currentColor" d="M316 32 L316 196 L480 196 L480 316 L316 316 L316 480 L196 480 L196 316 L32 316 L32 196 L196 196 L196 32 Z"/>
52508
- </symbol>
52509
- <!-- ellipsis-vertical (unfold the floating toolbar).
52510
- The strip it stands for is a vertical stack, and a vertical
52511
- ellipsis is what "there is more of this here" is drawn as
52512
- everywhere else. -->
52513
- <symbol id="g6-icon-toolbar-show" viewBox="0 0 128 512">
52514
- <path fill="currentColor" d="M64 360a56 56 0 1 0 0 112 56 56 0 1 0 0-112zm0-160a56 56 0 1 0 0 112 56 56 0 1 0 0-112zM120 96A56 56 0 1 0 8 96a56 56 0 1 0 112 0z"/>
52515
- </symbol>
52516
- <!-- xmark (fold the floating toolbar away).
52517
- Not a chevron: the two toolbars sit on OPPOSITE edges, so a
52518
- direction would point the wrong way on one of them. What the
52519
- button does is close an overlay, and that is an x. -->
52520
- <symbol id="g6-icon-toolbar-hide" viewBox="0 0 384 512">
52521
- <path fill="currentColor" d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"/>
52522
- </symbol>
52523
- <!-- dashed marquee (selection mode).
52524
- The band ITSELF, because that is what the button turns on: a
52525
- drag on the canvas draws one and a tap picks a card. Not the
52526
- fit-to-selection glyph next to it in the other toolbar -- that
52527
- one is solid brackets around a solid object and means "put the
52528
- camera on what is picked", which is the opposite end of the
52529
- gesture. Dashes: 16 segments of 59 with gaps of 36 over a
52530
- perimeter of 1520, so they land on the corners. -->
52531
- <symbol id="g6-icon-select-mode" viewBox="0 0 512 512">
52532
- <rect x="46" y="86" width="420" height="340" fill="none"
52533
- stroke="currentColor" stroke-width="40"
52534
- stroke-dasharray="59 36"/>
52535
- </symbol>
52536
- <!-- location-crosshairs (anchor the camera on one element).
52537
- The SAME path as the DOM toolbars and their yi-location-crosshairs
52538
- mask: the two toolbars sit in one console, and a control that
52539
- does one thing has to be drawn one way. -->
52540
- <symbol id="g6-icon-anchor" viewBox="0 0 576 512">
52541
- <path fill="currentColor" d="M288-16c17.7 0 32 14.3 32 32l0 18.3c98.1 14 175.7 91.6 189.7 189.7l18.3 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-18.3 0c-14 98.1-91.6 175.7-189.7 189.7l0 18.3c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-18.3C157.9 463.7 80.3 386.1 66.3 288L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l18.3 0C80.3 125.9 157.9 48.3 256 34.3L256 16c0-17.7 14.3-32 32-32zM128 256a160 160 0 1 0 320 0 160 160 0 1 0 -320 0zm160-96a96 96 0 1 1 0 192 96 96 0 1 1 0-192z"/>
52542
- </symbol>
52543
- <!-- floppy-disk (save) -->
52544
- <symbol id="g6-icon-save" viewBox="0 0 448 512">
52545
- <path fill="currentColor" d="M64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l320 0c35.3 0 64-28.7 64-64l0-242.7c0-17-6.7-33.3-18.7-45.3L352 50.7C340 38.7 323.7 32 306.7 32L64 32zm32 96c0-17.7 14.3-32 32-32l160 0c17.7 0 32 14.3 32 32l0 64c0 17.7-14.3 32-32 32l-160 0c-17.7 0-32-14.3-32-32l0-64zM224 288a64 64 0 1 1 0 128 64 64 0 1 1 0-128z"/>
52546
- </symbol>
52547
- </svg>`;
52548
- function inject_svg_icons() {
52549
- if (document.getElementById(CUSTOM_SVG_ICONS_ID)) return;
52550
- const div = document.createElement("div");
52551
- div.id = CUSTOM_SVG_ICONS_ID;
52552
- div.style.display = "none";
52553
- div.innerHTML = ICONS;
52554
- document.body.appendChild(div);
52555
- }
52556
- //#endregion
52557
52622
  //#region src/g6_brush_select_owned.js
52558
52623
  /***********************************************************************
52559
52624
  * g6_brush_select_owned.js
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.23.52",
3
+ "version": "7.23.53",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",
@@ -29,7 +29,7 @@
29
29
  "devDependencies": {
30
30
  "@rollup/plugin-terser": "^1.0.0",
31
31
  "@vitest/coverage-v8": "^4.1.10",
32
- "@yuneta/gobj-js": "^7.16.1",
32
+ "@yuneta/gobj-js": "^7.16.3",
33
33
  "vite": "^8.2.1",
34
34
  "vitest": "^4.1.10"
35
35
  },
package/src/c_yui_form.js CHANGED
@@ -661,6 +661,7 @@ function build_form_field_conf(gobj, field_desc)
661
661
  break;
662
662
 
663
663
  case "image":
664
+ case "icon":
664
665
  case "string":
665
666
  field_conf.tag = 'input';
666
667
  field_conf.inputType = 'text';
@@ -1787,6 +1788,7 @@ function template2columns(gobj, columns, template, sub_elements)
1787
1788
  break;
1788
1789
 
1789
1790
  case "image":
1791
+ case "icon":
1790
1792
  case "string":
1791
1793
  // field_conf.tag = 'input';
1792
1794
  // field_conf.inputType = 'text';
@@ -2516,6 +2518,7 @@ function treedb_value_2_form_value(gobj, field_desc, value)
2516
2518
  case "date":
2517
2519
  case "color":
2518
2520
  case "image":
2521
+ case "icon":
2519
2522
  case "tel":
2520
2523
  case "template":
2521
2524
  case "table":
@@ -2653,6 +2656,7 @@ function form_value_2_treedb_value(gobj, field_desc, value)
2653
2656
  case "date":
2654
2657
  case "color":
2655
2658
  case "image":
2659
+ case "icon":
2656
2660
  case "tel":
2657
2661
  break;
2658
2662
  case "template":
@@ -116,3 +116,13 @@
116
116
  background: transparent !important;
117
117
  }
118
118
 
119
+
120
+ /* Cell of a col flagged `icon`: the glyph is a CSS mask sized in `em`,
121
+ * so it comes out at the row's font size -- smaller than the 18px the
122
+ * `image` cells next to it get. A touch larger, and centred on the row
123
+ * rather than on the text baseline. */
124
+ .ICON_CELL {
125
+ font-size: 1.25em;
126
+ line-height: 1;
127
+ vertical-align: middle;
128
+ }
@@ -86,6 +86,7 @@ import {
86
86
  } from "./yui_table_select.js";
87
87
 
88
88
  import {yui_table_filter_clear} from "./yui_table_filter_clear.js";
89
+ import {yui_icon_is_defined} from "./lib_icons.js";
89
90
  import {row_matches} from "./yui_row_search.js";
90
91
 
91
92
  import {t} from "i18next";
@@ -1284,6 +1285,14 @@ function create_tabulator(gobj)
1284
1285
  hozAlign = "center";
1285
1286
  colFormatter = "color";
1286
1287
  break;
1288
+ case "icon":
1289
+ /* The NAME of an icon of the app's set, not a file --
1290
+ * which is why `image` cannot stand in for it: it built
1291
+ * an `<img src="yi-bolt">` and drew a broken image. */
1292
+ hozAlign = "center";
1293
+ vertAlign = "middle";
1294
+ colFormatter = icon_formatter;
1295
+ break;
1287
1296
  case "object":
1288
1297
  case "dict":
1289
1298
  case "template":
@@ -1694,6 +1703,48 @@ function table__destroy(gobj)
1694
1703
  }
1695
1704
  }
1696
1705
 
1706
+ /************************************************************
1707
+ * Cell of a col flagged `icon`: the value is the NAME of an
1708
+ * icon of the app's set ("yi-bolt"), so it is DRAWN.
1709
+ *
1710
+ * Built as a DOM node and not as an HTML string: the value is
1711
+ * raw record data and must never be parsed as markup -- and
1712
+ * here it also becomes a CSS class, so it is filtered to the
1713
+ * shape of a class name before it gets near one.
1714
+ *
1715
+ * A name the set does not carry falls back to the TEXT of it.
1716
+ * The catch-all rule `[class^="yi-"]::before` paints a
1717
+ * currentColor box for any name, so drawing it anyway would
1718
+ * render a solid square -- a glyph nobody recognises rather
1719
+ * than a mistake somebody can fix.
1720
+ ************************************************************/
1721
+ function icon_formatter(cell)
1722
+ {
1723
+ let name = cell.getValue();
1724
+ if(!is_string(name) || empty_string(name)) {
1725
+ return "";
1726
+ }
1727
+ name = name.trim();
1728
+
1729
+ if(!/^[a-z0-9-]+$/.test(name) || !yui_icon_is_defined(name)) {
1730
+ /* The NAME, in plain grey, and no invented label around it: it
1731
+ * is a developer's problem (a schema naming a glyph the set
1732
+ * does not carry) and the name IS the whole diagnosis -- while
1733
+ * a sentence here would be one more i18n key for every app
1734
+ * that mounts this table. */
1735
+ return createElement2([
1736
+ "span",
1737
+ {class: "ICON_CELL_UNKNOWN is-size-7 has-text-grey", title: name},
1738
+ name
1739
+ ]);
1740
+ }
1741
+
1742
+ return createElement2([
1743
+ "span",
1744
+ {class: `ICON_CELL ${name}`, title: name, "aria-label": name}
1745
+ ]);
1746
+ }
1747
+
1697
1748
  /************************************************************
1698
1749
  * Cell of a col holding a JSON document (dict/list/blob/
1699
1750
  * template/coordinates/…): a one-line truncated preview,
@@ -1852,6 +1903,10 @@ function transform__treedb_value_2_table_value(gobj, col, value, row, field)
1852
1903
  // Handled by Tabulator's built-in "color" formatter (see colDef above)
1853
1904
  break;
1854
1905
 
1906
+ case "icon":
1907
+ // Handled by icon_formatter() (see colDef above)
1908
+ break;
1909
+
1855
1910
  case "image":
1856
1911
  // Handled by Tabulator's built-in "image" formatter (see colDef above)
1857
1912
  break;
package/src/lib_icons.js CHANGED
@@ -168,3 +168,54 @@ export function inject_svg_icons()
168
168
  div.innerHTML = ICONS;
169
169
  document.body.appendChild(div);
170
170
  }
171
+
172
+ /*
173
+ * Is `yi-<name>` a real glyph of the loaded set?
174
+ *
175
+ * It has to be ASKED, not looked up in a list: the set is a CSS file
176
+ * (`yui_icons.css`) that an app may extend or replace, and a list here
177
+ * would be a second copy of it, wrong the first time somebody adds a
178
+ * mask rule. And the question matters because the catch-all rule
179
+ * `[class^="yi-"]::before` paints a `currentColor` box for ANY name --
180
+ * so an undefined icon does not fail, it renders as a solid black
181
+ * square, which reads as a glyph nobody recognises rather than as a
182
+ * mistake.
183
+ *
184
+ * The probe is the real stylesheet: a detached element gets no styles,
185
+ * so it is attached, hidden, measured and removed. Cached by name --
186
+ * a table draws one icon per row and the answer cannot change without
187
+ * a reload.
188
+ */
189
+ const __icon_defined__ = {};
190
+
191
+ export function yui_icon_is_defined(name)
192
+ {
193
+ if(!name || typeof name !== "string") {
194
+ return false;
195
+ }
196
+ if(__icon_defined__[name] !== undefined) {
197
+ return __icon_defined__[name];
198
+ }
199
+
200
+ let defined = false;
201
+ try {
202
+ const el = document.createElement("i");
203
+ el.className = name;
204
+ el.style.position = "absolute";
205
+ el.style.visibility = "hidden";
206
+ el.style.pointerEvents = "none";
207
+ document.body.appendChild(el);
208
+ const st = window.getComputedStyle(el, "::before");
209
+ const mask = st.maskImage || st.webkitMaskImage || "";
210
+ defined = !!mask && mask !== "none";
211
+ document.body.removeChild(el);
212
+ } catch(e) {
213
+ /* No DOM to ask (jsdom without the stylesheet, a test): answer
214
+ * "not defined" so the caller falls back to showing the name,
215
+ * which is the honest half of the pair. */
216
+ defined = false;
217
+ }
218
+
219
+ __icon_defined__[name] = defined;
220
+ return defined;
221
+ }