@yuneta/gobj-ui 7.23.11 → 7.23.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -884,13 +884,31 @@ gesture to give them: G6 binds panning and the band to the same plain drag, so
884
884
  one of the two has to stand aside. The edit toolbar carries a **selection
885
885
  mode** toggle (the dashed marquee, next to `+`): while it is on, a tap picks a
886
886
  card and a drag on the background draws the band, and panning is what stands
887
- aside. It is deliberately a button and not a heuristic — the toolbar says which
887
+ aside. It looks **pressed** while it is on (`pressed_state`, an inverted
888
+ neutral chip) rather than taking one of the palette's colours: each of those
889
+ names a KIND of action, and `7.23.11` borrowed undo/redo's violet for it —
890
+ which put the same colour on two neighbouring buttons for two different
891
+ reasons, and carried the whole state change in the hairline of an outline
892
+ glyph. It is deliberately a button and not a heuristic — the toolbar says which
888
893
  of the two the graph is listening for, and turning it off gives the camera
889
894
  back. It is not device-specific: the same button spares a desktop reader the
890
895
  key. Leaving edition turns it off, and it is not persisted.
891
896
 
892
897
  **New key for consumers: `selection mode`.**
893
898
 
899
+ **The two selects of the toolbar speak the app's language** (`7.23.13`). They
900
+ rendered their raw names — `reading`, `edition`, `dagre`, `manual` — in every
901
+ language, because neither went through `t()` at all: not a missing key, a
902
+ missing call. The label is translated and carries its own `data-i18n`, so it
903
+ follows a language change; the option's `value` is now set EXPLICITLY, because
904
+ an `<option>` with no value answers with its own text and a translated label
905
+ would have sent `"Edición"` to the FSM as the mode to enter.
906
+
907
+ **New keys for consumers: `reading`, `operation`, `writing`, `edition`,
908
+ `manual`, `dagre`, `antv-dagre`, `d3-force`, `force-atlas2`.** A host that adds
909
+ a layout of its own gets its name untranslated, which is what all of them got
910
+ until now.
911
+
894
912
  ### Tabs opened at runtime, and the two decisions their url costs
895
913
 
896
914
  `yui_tab_routes.js`. A workspace whose tabs are opened by the operator —
@@ -20597,6 +20597,19 @@ function set_active_state($container, selector, set) {
20597
20597
  if (set) addClasses($container, selector, "color_active_state");
20598
20598
  else removeClasses($container, selector, "color_active_state");
20599
20599
  }
20600
+ /************************************************************
20601
+ * Set or reset the 'pressed' state of a TOGGLE.
20602
+ *
20603
+ * Not one of the colours above: each of those names a KIND of
20604
+ * action (create, pending, history, destructive), and a toggle
20605
+ * is not an action -- it is a state the control is IN. So it
20606
+ * looks pressed instead of changing category, which also keeps
20607
+ * it out of the way of a neighbour wearing the same hue.
20608
+ ************************************************************/
20609
+ function set_pressed_state($container, selector, set) {
20610
+ if (set) addClasses($container, selector, "pressed_state");
20611
+ else removeClasses($container, selector, "pressed_state");
20612
+ }
20600
20613
  /**
20601
20614
  * Returns a smart stroke color in `rgba()` format based on:
20602
20615
  * - The given fill color (hex or rgb[a])
@@ -48317,7 +48330,7 @@ function configure_toolbar_edit(gobj) {
48317
48330
  {
48318
48331
  id: "g6-icon-select-mode",
48319
48332
  value: "selection-mode",
48320
- className: "EV_TOGGLE_SELECTION_MODE" + (priv.selection_mode ? " color_active_state" : ""),
48333
+ className: "EV_TOGGLE_SELECTION_MODE" + (priv.selection_mode ? " pressed_state" : ""),
48321
48334
  title: (0, i18next.t)("selection mode")
48322
48335
  },
48323
48336
  {
@@ -49750,7 +49763,9 @@ function update_zoom_selection_button(gobj) {
49750
49763
  else disableElements($container, ".EV_ZOOM_SELECTION");
49751
49764
  }
49752
49765
  /************************************************************
49753
- * The selection mode is a state, so it has to LOOK like one.
49766
+ * The selection mode is a state, so it has to LOOK like one:
49767
+ * a PRESSED toggle, not a button wearing one of the palette's
49768
+ * action colours (see `pressed_state` in lib_graph.css).
49754
49769
  *
49755
49770
  * Toggled on the element rather than re-rendered with the
49756
49771
  * toolbar, for the same reason as the button above: a
@@ -49762,7 +49777,7 @@ function update_selection_mode_button(gobj) {
49762
49777
  let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
49763
49778
  if (!$container) return;
49764
49779
  if (!$container.querySelector(".EV_TOGGLE_SELECTION_MODE")) return;
49765
- set_active_state($container, ".EV_TOGGLE_SELECTION_MODE", priv.selection_mode);
49780
+ set_pressed_state($container, ".EV_TOGGLE_SELECTION_MODE", priv.selection_mode);
49766
49781
  }
49767
49782
  /************************************************************
49768
49783
  * Select a SET of nodes: what a marquee and a shift-click do.
@@ -53121,6 +53136,40 @@ function destroy_ui$1(gobj) {
53121
53136
  }
53122
53137
  }
53123
53138
  /************************************************************
53139
+ * The label of an option of the two selects of the toolbar.
53140
+ *
53141
+ * Both of them used to render their RAW names -- `reading`,
53142
+ * `edition`, `dagre`, `manual` -- in every language, because
53143
+ * neither went through `t()` at all. Not a missing key: a
53144
+ * missing call.
53145
+ *
53146
+ * Written as one literal per case, and deliberately not as
53147
+ * `t(name)`: a consumer's `validate-locales.mjs` reads
53148
+ * LITERALS, so a variable key is invisible to it -- the app
53149
+ * ships without the entry and nothing says so, because
53150
+ * i18next answers an unknown key with the key itself, which
53151
+ * is exactly the English word that was there before. The
53152
+ * same reason the keys are listed in the README.
53153
+ *
53154
+ * The default is what a host that adds a layout of its own
53155
+ * gets: the name it chose, which is what all of them got
53156
+ * until now.
53157
+ ************************************************************/
53158
+ function option_label(name) {
53159
+ switch (name) {
53160
+ case "reading": return (0, i18next.t)("reading");
53161
+ case "operation": return (0, i18next.t)("operation");
53162
+ case "writing": return (0, i18next.t)("writing");
53163
+ case "edition": return (0, i18next.t)("edition");
53164
+ case "manual": return (0, i18next.t)("manual");
53165
+ case "dagre": return (0, i18next.t)("dagre");
53166
+ case "antv-dagre": return (0, i18next.t)("antv-dagre");
53167
+ case "d3-force": return (0, i18next.t)("d3-force");
53168
+ case "force-atlas2": return (0, i18next.t)("force-atlas2");
53169
+ default: return name;
53170
+ }
53171
+ }
53172
+ /************************************************************
53124
53173
  *
53125
53174
  ************************************************************/
53126
53175
  function make_toolbar(gobj) {
@@ -53163,8 +53212,11 @@ function make_toolbar(gobj) {
53163
53212
  { class: "GRAPH_MODE_SELECT" },
53164
53213
  modes.map((item) => [
53165
53214
  "option",
53166
- {},
53167
- item
53215
+ {
53216
+ value: item,
53217
+ "data-i18n": item
53218
+ },
53219
+ option_label(item)
53168
53220
  ])
53169
53221
  ]],
53170
53222
  { change: (evt) => {
@@ -53503,7 +53555,8 @@ function populate_nodes_tree_options(gobj) {
53503
53555
  for (let name of layout_names) {
53504
53556
  let option = document.createElement("option");
53505
53557
  option.value = name;
53506
- option.textContent = name;
53558
+ option.setAttribute("data-i18n", name);
53559
+ option.textContent = option_label(name);
53507
53560
  $layout_select.appendChild(option);
53508
53561
  }
53509
53562
  let current_layout = (0, _yuneta_gobj_js.gobj_read_str_attr)(priv.gobj_nodes_tree, "layout");
@@ -63694,6 +63747,7 @@ exports.rolling_bounds = rolling_bounds;
63694
63747
  exports.safe_locale = safe_locale;
63695
63748
  exports.set_active_state = set_active_state;
63696
63749
  exports.set_cancel_state = set_cancel_state;
63750
+ exports.set_pressed_state = set_pressed_state;
63697
63751
  exports.set_submit_state = set_submit_state;
63698
63752
  exports.setup_dev = setup_dev;
63699
63753
  exports.setup_frontend_view = setup_frontend_view;
@@ -20584,6 +20584,19 @@ function set_active_state($container, selector, set) {
20584
20584
  if (set) addClasses($container, selector, "color_active_state");
20585
20585
  else removeClasses($container, selector, "color_active_state");
20586
20586
  }
20587
+ /************************************************************
20588
+ * Set or reset the 'pressed' state of a TOGGLE.
20589
+ *
20590
+ * Not one of the colours above: each of those names a KIND of
20591
+ * action (create, pending, history, destructive), and a toggle
20592
+ * is not an action -- it is a state the control is IN. So it
20593
+ * looks pressed instead of changing category, which also keeps
20594
+ * it out of the way of a neighbour wearing the same hue.
20595
+ ************************************************************/
20596
+ function set_pressed_state($container, selector, set) {
20597
+ if (set) addClasses($container, selector, "pressed_state");
20598
+ else removeClasses($container, selector, "pressed_state");
20599
+ }
20587
20600
  /**
20588
20601
  * Returns a smart stroke color in `rgba()` format based on:
20589
20602
  * - The given fill color (hex or rgb[a])
@@ -48304,7 +48317,7 @@ function configure_toolbar_edit(gobj) {
48304
48317
  {
48305
48318
  id: "g6-icon-select-mode",
48306
48319
  value: "selection-mode",
48307
- className: "EV_TOGGLE_SELECTION_MODE" + (priv.selection_mode ? " color_active_state" : ""),
48320
+ className: "EV_TOGGLE_SELECTION_MODE" + (priv.selection_mode ? " pressed_state" : ""),
48308
48321
  title: t("selection mode")
48309
48322
  },
48310
48323
  {
@@ -49737,7 +49750,9 @@ function update_zoom_selection_button(gobj) {
49737
49750
  else disableElements($container, ".EV_ZOOM_SELECTION");
49738
49751
  }
49739
49752
  /************************************************************
49740
- * The selection mode is a state, so it has to LOOK like one.
49753
+ * The selection mode is a state, so it has to LOOK like one:
49754
+ * a PRESSED toggle, not a button wearing one of the palette's
49755
+ * action colours (see `pressed_state` in lib_graph.css).
49741
49756
  *
49742
49757
  * Toggled on the element rather than re-rendered with the
49743
49758
  * toolbar, for the same reason as the button above: a
@@ -49749,7 +49764,7 @@ function update_selection_mode_button(gobj) {
49749
49764
  let $container = gobj_read_attr(gobj, "$container");
49750
49765
  if (!$container) return;
49751
49766
  if (!$container.querySelector(".EV_TOGGLE_SELECTION_MODE")) return;
49752
- set_active_state($container, ".EV_TOGGLE_SELECTION_MODE", priv.selection_mode);
49767
+ set_pressed_state($container, ".EV_TOGGLE_SELECTION_MODE", priv.selection_mode);
49753
49768
  }
49754
49769
  /************************************************************
49755
49770
  * Select a SET of nodes: what a marquee and a shift-click do.
@@ -53108,6 +53123,40 @@ function destroy_ui$1(gobj) {
53108
53123
  }
53109
53124
  }
53110
53125
  /************************************************************
53126
+ * The label of an option of the two selects of the toolbar.
53127
+ *
53128
+ * Both of them used to render their RAW names -- `reading`,
53129
+ * `edition`, `dagre`, `manual` -- in every language, because
53130
+ * neither went through `t()` at all. Not a missing key: a
53131
+ * missing call.
53132
+ *
53133
+ * Written as one literal per case, and deliberately not as
53134
+ * `t(name)`: a consumer's `validate-locales.mjs` reads
53135
+ * LITERALS, so a variable key is invisible to it -- the app
53136
+ * ships without the entry and nothing says so, because
53137
+ * i18next answers an unknown key with the key itself, which
53138
+ * is exactly the English word that was there before. The
53139
+ * same reason the keys are listed in the README.
53140
+ *
53141
+ * The default is what a host that adds a layout of its own
53142
+ * gets: the name it chose, which is what all of them got
53143
+ * until now.
53144
+ ************************************************************/
53145
+ function option_label(name) {
53146
+ switch (name) {
53147
+ case "reading": return t("reading");
53148
+ case "operation": return t("operation");
53149
+ case "writing": return t("writing");
53150
+ case "edition": return t("edition");
53151
+ case "manual": return t("manual");
53152
+ case "dagre": return t("dagre");
53153
+ case "antv-dagre": return t("antv-dagre");
53154
+ case "d3-force": return t("d3-force");
53155
+ case "force-atlas2": return t("force-atlas2");
53156
+ default: return name;
53157
+ }
53158
+ }
53159
+ /************************************************************
53111
53160
  *
53112
53161
  ************************************************************/
53113
53162
  function make_toolbar(gobj) {
@@ -53150,8 +53199,11 @@ function make_toolbar(gobj) {
53150
53199
  { class: "GRAPH_MODE_SELECT" },
53151
53200
  modes.map((item) => [
53152
53201
  "option",
53153
- {},
53154
- item
53202
+ {
53203
+ value: item,
53204
+ "data-i18n": item
53205
+ },
53206
+ option_label(item)
53155
53207
  ])
53156
53208
  ]],
53157
53209
  { change: (evt) => {
@@ -53490,7 +53542,8 @@ function populate_nodes_tree_options(gobj) {
53490
53542
  for (let name of layout_names) {
53491
53543
  let option = document.createElement("option");
53492
53544
  option.value = name;
53493
- option.textContent = name;
53545
+ option.setAttribute("data-i18n", name);
53546
+ option.textContent = option_label(name);
53494
53547
  $layout_select.appendChild(option);
53495
53548
  }
53496
53549
  let current_layout = gobj_read_str_attr(priv.gobj_nodes_tree, "layout");
@@ -63623,6 +63676,6 @@ function setup_frontend_view(self) {
63623
63676
  return win;
63624
63677
  }
63625
63678
  //#endregion
63626
- export { EditControl, MarkerControl, YUI_PERIODS, YUI_PERIODS_DEFAULT, YUI_ROLLING, addClasses, apply_dev_traces, attach_clear, build_dev_panel, dev_window_was_open, disableElements, enableElements, epoch_to_local_input, epoch_to_ms, expose_view_container, fmt_epoch, getStrokeColor, infer_period, info_traffic, inject_svg_icons, is_current_period, iso_week, local_input_to_epoch, ms_to_epoch, period_bounds, period_bounds_epoch, period_label, period_name, period_shift, period_spec, period_start, refresh_clear, register_c_g6_nodes_tree, register_c_yui_form, register_c_yui_gobj_tree_js, register_c_yui_json, register_c_yui_json_graph, register_c_yui_map, register_c_yui_nav, register_c_yui_pager, register_c_yui_period, register_c_yui_schema_editor, register_c_yui_service_view, register_c_yui_shell, register_c_yui_treedb_graph, register_c_yui_treedb_schema, register_c_yui_treedb_topic_with_form, register_c_yui_treedb_topics, register_c_yui_uplot, register_c_yui_window, register_c_yui_window_manager, register_c_yui_wizard, removeChildElements, removeClasses, rolling_bounds, safe_locale, set_active_state, set_cancel_state, set_submit_state, setup_dev, setup_frontend_view, toggleClasses, yui_is_dark, yui_mount_service_view, yui_shell_close_drawer, yui_shell_close_dropdown, yui_shell_confirm_danger, yui_shell_confirm_ok, yui_shell_confirm_yesno, yui_shell_confirm_yesnocancel, yui_shell_navigate, yui_shell_open_drawer, yui_shell_overlay_dismissed, yui_shell_pop_escape, yui_shell_push_escape, yui_shell_refresh_avatars, yui_shell_register_event_handler, yui_shell_register_overlay, yui_shell_set_avatar_provider, yui_shell_set_connection_state, yui_shell_set_sub_routes, yui_shell_set_toolbar_item_badge, yui_shell_set_toolbar_item_icon, yui_shell_set_translator, yui_shell_show_error, yui_shell_show_info, yui_shell_show_modal, yui_shell_show_route_map, yui_shell_show_warning, yui_shell_toggle_drawer, yui_shell_unpark_route, yui_theme_now, yui_toolbar, yui_watch_theme };
63679
+ export { EditControl, MarkerControl, YUI_PERIODS, YUI_PERIODS_DEFAULT, YUI_ROLLING, addClasses, apply_dev_traces, attach_clear, build_dev_panel, dev_window_was_open, disableElements, enableElements, epoch_to_local_input, epoch_to_ms, expose_view_container, fmt_epoch, getStrokeColor, infer_period, info_traffic, inject_svg_icons, is_current_period, iso_week, local_input_to_epoch, ms_to_epoch, period_bounds, period_bounds_epoch, period_label, period_name, period_shift, period_spec, period_start, refresh_clear, register_c_g6_nodes_tree, register_c_yui_form, register_c_yui_gobj_tree_js, register_c_yui_json, register_c_yui_json_graph, register_c_yui_map, register_c_yui_nav, register_c_yui_pager, register_c_yui_period, register_c_yui_schema_editor, register_c_yui_service_view, register_c_yui_shell, register_c_yui_treedb_graph, register_c_yui_treedb_schema, register_c_yui_treedb_topic_with_form, register_c_yui_treedb_topics, register_c_yui_uplot, register_c_yui_window, register_c_yui_window_manager, register_c_yui_wizard, removeChildElements, removeClasses, rolling_bounds, safe_locale, set_active_state, set_cancel_state, set_pressed_state, set_submit_state, setup_dev, setup_frontend_view, toggleClasses, yui_is_dark, yui_mount_service_view, yui_shell_close_drawer, yui_shell_close_dropdown, yui_shell_confirm_danger, yui_shell_confirm_ok, yui_shell_confirm_yesno, yui_shell_confirm_yesnocancel, yui_shell_navigate, yui_shell_open_drawer, yui_shell_overlay_dismissed, yui_shell_pop_escape, yui_shell_push_escape, yui_shell_refresh_avatars, yui_shell_register_event_handler, yui_shell_register_overlay, yui_shell_set_avatar_provider, yui_shell_set_connection_state, yui_shell_set_sub_routes, yui_shell_set_toolbar_item_badge, yui_shell_set_toolbar_item_icon, yui_shell_set_translator, yui_shell_show_error, yui_shell_show_info, yui_shell_show_modal, yui_shell_show_route_map, yui_shell_show_warning, yui_shell_toggle_drawer, yui_shell_unpark_route, yui_theme_now, yui_toolbar, yui_watch_theme };
63627
63680
 
63628
63681
  //# sourceMappingURL=gobj-ui.es.js.map
package/index.js CHANGED
@@ -114,7 +114,7 @@ export {
114
114
  /*
115
115
  * Libraries and utilities
116
116
  */
117
- export { addClasses, removeClasses, toggleClasses, removeChildElements, disableElements, enableElements, set_submit_state, set_cancel_state, set_active_state, getStrokeColor } from "./src/lib_graph.js";
117
+ export { addClasses, removeClasses, toggleClasses, removeChildElements, disableElements, enableElements, set_submit_state, set_cancel_state, set_active_state, set_pressed_state, getStrokeColor } from "./src/lib_graph.js";
118
118
  export { inject_svg_icons } from "./src/lib_icons.js";
119
119
  export { EditControl, MarkerControl } from "./src/lib_maplibre.js";
120
120
  export { yui_toolbar } from "./src/yui_toolbar.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.23.11",
3
+ "version": "7.23.13",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",
@@ -79,6 +79,7 @@ import {
79
79
  set_submit_state,
80
80
  set_cancel_state,
81
81
  set_active_state,
82
+ set_pressed_state,
82
83
  getStrokeColor,
83
84
  } from "./lib_graph.js";
84
85
 
@@ -1340,7 +1341,7 @@ function configure_toolbar_edit(gobj)
1340
1341
  {
1341
1342
  id: 'g6-icon-select-mode', value: 'selection-mode',
1342
1343
  className: 'EV_TOGGLE_SELECTION_MODE' +
1343
- (priv.selection_mode? ' color_active_state' : ''),
1344
+ (priv.selection_mode? ' pressed_state' : ''),
1344
1345
  title: t('selection mode')
1345
1346
  },
1346
1347
  { id: 'g6-icon-save', value: 'save', className: 'EV_SAVE_GRAPH', title: t('save'), disabled: true },
@@ -3608,7 +3609,9 @@ function update_zoom_selection_button(gobj)
3608
3609
  }
3609
3610
 
3610
3611
  /************************************************************
3611
- * The selection mode is a state, so it has to LOOK like one.
3612
+ * The selection mode is a state, so it has to LOOK like one:
3613
+ * a PRESSED toggle, not a button wearing one of the palette's
3614
+ * action colours (see `pressed_state` in lib_graph.css).
3612
3615
  *
3613
3616
  * Toggled on the element rather than re-rendered with the
3614
3617
  * toolbar, for the same reason as the button above: a
@@ -3628,7 +3631,7 @@ function update_selection_mode_button(gobj)
3628
3631
  return; /* no edit toolbar: not in edition, or folded away */
3629
3632
  }
3630
3633
 
3631
- set_active_state($container, ".EV_TOGGLE_SELECTION_MODE", priv.selection_mode);
3634
+ set_pressed_state($container, ".EV_TOGGLE_SELECTION_MODE", priv.selection_mode);
3632
3635
  }
3633
3636
 
3634
3637
  /************************************************************
@@ -452,6 +452,56 @@ function destroy_ui(gobj)
452
452
  }
453
453
  }
454
454
 
455
+ /************************************************************
456
+ * The label of an option of the two selects of the toolbar.
457
+ *
458
+ * Both of them used to render their RAW names -- `reading`,
459
+ * `edition`, `dagre`, `manual` -- in every language, because
460
+ * neither went through `t()` at all. Not a missing key: a
461
+ * missing call.
462
+ *
463
+ * Written as one literal per case, and deliberately not as
464
+ * `t(name)`: a consumer's `validate-locales.mjs` reads
465
+ * LITERALS, so a variable key is invisible to it -- the app
466
+ * ships without the entry and nothing says so, because
467
+ * i18next answers an unknown key with the key itself, which
468
+ * is exactly the English word that was there before. The
469
+ * same reason the keys are listed in the README.
470
+ *
471
+ * The default is what a host that adds a layout of its own
472
+ * gets: the name it chose, which is what all of them got
473
+ * until now.
474
+ ************************************************************/
475
+ function option_label(name)
476
+ {
477
+ switch(name) {
478
+ /* Operation modes (`operation_modes` attr). */
479
+ case "reading":
480
+ return t("reading");
481
+ case "operation":
482
+ return t("operation");
483
+ case "writing":
484
+ return t("writing");
485
+ case "edition":
486
+ return t("edition");
487
+
488
+ /* Layouts (`layout_names` of the G6 child). */
489
+ case "manual":
490
+ return t("manual");
491
+ case "dagre":
492
+ return t("dagre");
493
+ case "antv-dagre":
494
+ return t("antv-dagre");
495
+ case "d3-force":
496
+ return t("d3-force");
497
+ case "force-atlas2":
498
+ return t("force-atlas2");
499
+
500
+ default:
501
+ return name;
502
+ }
503
+ }
504
+
455
505
  /************************************************************
456
506
  *
457
507
  ************************************************************/
@@ -468,7 +518,14 @@ function make_toolbar(gobj)
468
518
  * one that draws the create / delete / link affordances. */
469
519
  modes = modes.filter(mode => mode !== "edition");
470
520
  }
471
- let mode_options = modes.map(item => ['option', {}, item]);
521
+ /* `value` EXPLICIT, and that is not decoration: an <option>
522
+ * with no value attribute answers with its own TEXT, so the
523
+ * moment the label is translated `evt.target.value` becomes
524
+ * "Edición" and the mode the FSM is told to enter is a word
525
+ * no `switch` of this gclass knows. */
526
+ let mode_options = modes.map(item =>
527
+ ['option', {value: item, 'data-i18n': item}, option_label(item)]
528
+ );
472
529
 
473
530
  /*
474
531
  * Left: layout and mode selectors
@@ -876,7 +933,12 @@ function populate_nodes_tree_options(gobj)
876
933
  for(let name of layout_names) {
877
934
  let option = document.createElement('option');
878
935
  option.value = name;
879
- option.textContent = name;
936
+ /* The key travels in the attribute so a language change
937
+ * re-translates it: `refresh_language()` only touches a
938
+ * node that carries its own key, and this select is built
939
+ * once, after the child answers with its layouts. */
940
+ option.setAttribute('data-i18n', name);
941
+ option.textContent = option_label(name);
880
942
  $layout_select.appendChild(option);
881
943
  }
882
944
  // Restore persisted layout selection
package/src/lib_graph.css CHANGED
@@ -177,6 +177,32 @@
177
177
  background-color: var(--bulma-background, #f0f0f0);
178
178
  }
179
179
 
180
+ /*
181
+ * A TOGGLE that is on looks PRESSED, it does not take a colour from
182
+ * the palette at the top of this file: each of those names a kind of
183
+ * ACTION, and "the graph is listening for a selection" is not one --
184
+ * borrowing undo/redo's violet for it put the same colour on two
185
+ * neighbouring buttons for two different reasons.
186
+ *
187
+ * Inverted neutral, and deliberately hue-free: it cannot be mistaken
188
+ * for the hover tint declared just above (a much lighter wash of the
189
+ * same surface), it reads at a glance even when the glyph is a thin
190
+ * outline rather than a solid silhouette, and it says what it says
191
+ * without a hue -- which is the same reason the palette above is
192
+ * documented as colour-blind safe.
193
+ *
194
+ * The `:hover` half is not decoration: without it, hovering a pressed
195
+ * button would hand it back to the rule above (equal specificity,
196
+ * declared earlier, so this one wins only where both match) and the
197
+ * toggle would appear to switch off under the pointer.
198
+ */
199
+ .g6-toolbar.g6-toolbar-large .g6-toolbar-item.pressed_state,
200
+ .g6-toolbar.g6-toolbar-large .g6-toolbar-item.pressed_state:hover {
201
+ background-color: var(--bulma-text, #2e333d);
202
+ color: var(--bulma-background, #ffffff);
203
+ border-radius: 4px;
204
+ }
205
+
180
206
  /*
181
207
  * Touch: the context menu is a LIST OF COMMANDS, and G6 sizes its
182
208
  * rows with `padding: 8px 12px` -- 34px, which is a mouse row. The
package/src/lib_graph.js CHANGED
@@ -109,6 +109,24 @@ function set_active_state($container, selector, set)
109
109
  }
110
110
  }
111
111
 
112
+ /************************************************************
113
+ * Set or reset the 'pressed' state of a TOGGLE.
114
+ *
115
+ * Not one of the colours above: each of those names a KIND of
116
+ * action (create, pending, history, destructive), and a toggle
117
+ * is not an action -- it is a state the control is IN. So it
118
+ * looks pressed instead of changing category, which also keeps
119
+ * it out of the way of a neighbour wearing the same hue.
120
+ ************************************************************/
121
+ function set_pressed_state($container, selector, set)
122
+ {
123
+ if(set) {
124
+ addClasses($container, selector, "pressed_state");
125
+ } else {
126
+ removeClasses($container, selector, "pressed_state");
127
+ }
128
+ }
129
+
112
130
  /**
113
131
  * Returns a smart stroke color in `rgba()` format based on:
114
132
  * - The given fill color (hex or rgb[a])
@@ -187,5 +205,6 @@ export {
187
205
  set_submit_state,
188
206
  set_cancel_state,
189
207
  set_active_state,
208
+ set_pressed_state,
190
209
  getStrokeColor,
191
210
  };