@yuneta/gobj-ui 7.26.25 → 7.26.27

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
@@ -3600,19 +3600,62 @@ directory:
3600
3600
  }
3601
3601
  ```
3602
3602
 
3603
- It also scans the gobj-ui modules the app mounts, deep or through the barrel:
3604
- **the library translates through the APP's i18next**, so every key it asks for
3605
- must be defined by the app. The library it scans is the one it ships in, the
3606
- package the app builds with. Code and catalogs shared by several apps are
3607
- named with `--src <dir>` (repeatable) and `--locales <dir>` (yunovatios:
3603
+ It also scans the gobj-ui modules the app mounts -- deep, through the barrel,
3604
+ or by a dynamic `import()`: **the library translates through the APP's
3605
+ i18next**, so every key it asks for must be defined by the app. The library it
3606
+ scans is the one it ships in, the package the app builds with. The app's own
3607
+ source is read recursively. Code and catalogs shared by several apps are named
3608
+ with `--src <dir>` (repeatable) and `--locales <dir>` (yunovatios:
3608
3609
  `--src ../gui-common/src --locales ../gui-common/src/locales`); `--config`
3609
3610
  names a shell declaration other than `src/app_config.json`.
3610
3611
 
3612
+ What is particular to an app goes in ITS `package.json`, not in the script:
3613
+ properties whose value is a key, and properties whose value is a list of keys
3614
+ (yunovatios hands its orchestrator `app_title: "central"` and
3615
+ `welcome_features: [...]`):
3616
+
3617
+ ```json
3618
+ "validate-locales": {
3619
+ "attr_keys": ["app_title", "app_subtitle", "welcome_title", "welcome_lead"],
3620
+ "array_keys": ["welcome_features"]
3621
+ }
3622
+ ```
3623
+
3624
+ Plurals are compared by language (since `7.26.26`): `songs_one` /
3625
+ `songs_few` / `songs_many` / `songs_other` are one key, and each locale must
3626
+ carry the categories of ITS language (`Intl.PluralRules`: English `one`,
3627
+ `other`; Russian `one`, `few`, `many`, `other`; Chinese `other`). The key with
3628
+ no suffix serves `other` and `many`; `zero`, `one`, `two` and `few` need their
3629
+ own form. That is a policy of GRAMMAR, not a need of i18next, which falls back
3630
+ to the bare key for any form that is missing: a Russian count of 3 rendered
3631
+ with the bare key reads wrong, and the check says so. A key that only ends
3632
+ like a form (`pick_one` alone) is a plain key; ordinals (`place_ordinal_one`)
3633
+ are checked with the ordinal categories of each language. A value of the shell
3634
+ declaration is a literal when it is the endonym of one of the app's locales
3635
+ (the `name` its catalog exports: `"中文"`, `"español"`); any other lower-case
3636
+ text is a key, `"configuración"` included.
3637
+
3638
+ **A key that reaches `t()` as data is PUBLISHED by its module** (since
3639
+ `7.26.27`): an exported `<NAME>_I18N_KEYS` array of string literals, which
3640
+ `validate-locales` reads in every module the app mounts and asks the locales
3641
+ for. `yui_dev.js` publishes the 51 keys of the Developer window
3642
+ (`YUI_DEV_I18N_KEYS`) -- they used to be a comment each consumer copied, and
3643
+ one consumer lacked 35 --, `c_g6_nodes_tree.js` those of its shape tables and
3644
+ popover labels (`G6_NODES_TREE_I18N_KEYS`). A module that hands a key to `t()`
3645
+ by variable adds it to such a list:
3646
+
3647
+ ```js
3648
+ export const MY_VIEW_I18N_KEYS = ['shape', 'radius', 'apply to'];
3649
+ ```
3650
+
3611
3651
  Up to `7.26.24` each app carried its own copy, and the copies had drifted into
3612
3652
  three families: only one read the codes of the schema editor, only the other
3613
3653
  two the barrel imports, and two read `t('topic') + ':'` as a key built by
3614
3654
  concatenation and skipped it -- so the gobj tree's *"topic:"* went untranslated
3615
- in wattyzer and yunovatios. An app keeps no copy now.
3655
+ in wattyzer and yunovatios. No app keeps a copy now, but one: `test-app`, this
3656
+ library's own demo, whose catalog has English as the source (a key IS the
3657
+ English text, Title Case included) and so follows other rules, in its own
3658
+ `test-app/scripts/validate-locales.mjs`.
3616
3659
 
3617
3660
  ### Dates: never hand-roll them again
3618
3661
 
@@ -7181,11 +7181,11 @@ function yui_file_control(gobj, { name, value, readonly, accept, on_pick }) {
7181
7181
  if (picked) {
7182
7182
  $state.classList.add("is-picked");
7183
7183
  $state.setAttribute("data-i18n", "not saved yet");
7184
- $state.textContent = "not saved yet";
7184
+ $state.textContent = (0, i18next.t)("not saved yet");
7185
7185
  } else if (!kept) {
7186
7186
  $state.classList.add("is-empty");
7187
7187
  $state.setAttribute("data-i18n", "no file");
7188
- $state.textContent = "no file";
7188
+ $state.textContent = (0, i18next.t)("no file");
7189
7189
  }
7190
7190
  $clear.hidden = readonly || !picked && !kept;
7191
7191
  $pick.hidden = !!readonly;
@@ -8988,7 +8988,7 @@ function destroy_widgets(gobj, $container) {
8988
8988
  * ids would break the association for both. The key is the
8989
8989
  * label's own, so a language change reaches it.
8990
8990
  ************************************************************/
8991
- function name_form_control($field, conf) {
8991
+ function name_form_control$1($field, conf) {
8992
8992
  if (!$field || typeof $field.querySelector !== "function" || !conf) return;
8993
8993
  let key = conf.label_i18n || conf.label || "";
8994
8994
  if (!key) return;
@@ -9059,7 +9059,7 @@ function build_html_form(gobj, $form, prefix, template) {
9059
9059
  if (placeholders[key]) html_field_conf.placeholder = placeholders[key];
9060
9060
  if (html_field_conf.tag) {
9061
9061
  let $field = create_form_field(gobj, $form, prefix, field_desc, html_field_conf);
9062
- name_form_control($field, html_field_conf);
9062
+ name_form_control$1($field, html_field_conf);
9063
9063
  $form.appendChild($field);
9064
9064
  }
9065
9065
  });
@@ -63793,19 +63793,34 @@ function touch_control_css() {
63793
63793
  if (!coarse_pointer()) return "";
63794
63794
  return "min-height:44px;font-size:16px;";
63795
63795
  }
63796
+ var form_control_seq = 0;
63796
63797
  function create_form_label(parent, text) {
63797
63798
  let label = document.createElement("label");
63798
63799
  label.textContent = (0, i18next.t)(text);
63800
+ label.setAttribute("data-i18n", text);
63799
63801
  label.style.cssText = "display:block;margin-bottom:4px;font-weight:500;";
63800
63802
  parent.appendChild(label);
63801
63803
  return label;
63802
63804
  }
63805
+ function name_form_control(parent, control) {
63806
+ let label = parent.lastElementChild;
63807
+ if (!label || label.tagName !== "LABEL") return;
63808
+ let key = label.getAttribute("data-i18n");
63809
+ if (!key) return;
63810
+ control.id = "g6-form-control-" + ++form_control_seq;
63811
+ label.htmlFor = control.id;
63812
+ control.setAttribute("title", (0, i18next.t)(key));
63813
+ control.setAttribute("data-i18n-title", key);
63814
+ control.setAttribute("aria-label", (0, i18next.t)(key));
63815
+ control.setAttribute("data-i18n-aria-label", key);
63816
+ }
63803
63817
  function create_form_color_input(parent, value, onInput) {
63804
63818
  let input = document.createElement("input");
63805
63819
  input.type = "color";
63806
63820
  input.value = value;
63807
63821
  input.style.cssText = "width:100%;height:30px;padding:0;border:1px solid var(--bulma-border-weak, #d9d9d9);border-radius:4px;cursor:pointer;margin-bottom:10px;" + touch_control_css();
63808
63822
  if (onInput) input.addEventListener("input", onInput);
63823
+ name_form_control(parent, input);
63809
63824
  parent.appendChild(input);
63810
63825
  return input;
63811
63826
  }
@@ -63817,6 +63832,7 @@ function create_form_number_input(parent, value, min, max, onInput) {
63817
63832
  input.value = value;
63818
63833
  input.style.cssText = "width:100%;padding:4px 6px;background:var(--bulma-scheme-main-bis, #fff);color:var(--bulma-text-strong, #333);border:1px solid var(--bulma-border-weak, #d9d9d9);border-radius:4px;box-sizing:border-box;margin-bottom:10px;" + touch_control_css();
63819
63834
  if (onInput) input.addEventListener("input", onInput);
63835
+ name_form_control(parent, input);
63820
63836
  parent.appendChild(input);
63821
63837
  return input;
63822
63838
  }
@@ -63826,9 +63842,11 @@ function create_form_select(parent, options, marginBottom) {
63826
63842
  for (let opt of options) {
63827
63843
  let o = document.createElement("option");
63828
63844
  o.value = opt.value;
63829
- o.textContent = opt.label;
63845
+ o.textContent = (0, i18next.t)(opt.i18n);
63846
+ o.setAttribute("data-i18n", opt.i18n);
63830
63847
  select.appendChild(o);
63831
63848
  }
63849
+ name_form_control(parent, select);
63832
63850
  parent.appendChild(select);
63833
63851
  return select;
63834
63852
  }
@@ -63836,9 +63854,14 @@ var BTN_STYLE_CANCEL = "flex:1;padding:6px;background:var(--bulma-scheme-main-bi
63836
63854
  function create_form_button_row(parent, buttons) {
63837
63855
  let btnRow = document.createElement("div");
63838
63856
  btnRow.style.cssText = "display:flex;gap:8px;";
63839
- for (let { text, style, onClick } of buttons) {
63857
+ for (let { i18n, style, onClick } of buttons) {
63840
63858
  let btn = document.createElement("button");
63841
- btn.textContent = (0, i18next.t)(text);
63859
+ btn.textContent = (0, i18next.t)(i18n);
63860
+ btn.setAttribute("data-i18n", i18n);
63861
+ btn.setAttribute("title", (0, i18next.t)(i18n));
63862
+ btn.setAttribute("data-i18n-title", i18n);
63863
+ btn.setAttribute("aria-label", (0, i18next.t)(i18n));
63864
+ btn.setAttribute("data-i18n-aria-label", i18n);
63842
63865
  btn.style.cssText = style + touch_control_css();
63843
63866
  btn.addEventListener("click", (e) => {
63844
63867
  e.stopPropagation();
@@ -63872,11 +63895,11 @@ function show_confirm_popover(gobj, target_el, message, confirm_text, confirm_co
63872
63895
  msg.textContent = message;
63873
63896
  popover.appendChild(msg);
63874
63897
  create_form_button_row(popover, [{
63875
- text: "cancel",
63898
+ i18n: "cancel",
63876
63899
  style: BTN_STYLE_CANCEL,
63877
63900
  onClick: () => hide_overlay(gobj, priv_key)
63878
63901
  }, {
63879
- text: confirm_text,
63902
+ i18n: confirm_text,
63880
63903
  style: "flex:1;padding:6px;background:" + confirm_color + ";color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
63881
63904
  onClick: onConfirm
63882
63905
  }]);
@@ -64582,7 +64605,7 @@ function show_port_popover(gobj) {
64582
64605
  let shapeSelect = create_form_select(popover, PORT_SHAPES.map((shape) => {
64583
64606
  return {
64584
64607
  value: shape,
64585
- label: (0, i18next.t)(shape)
64608
+ i18n: shape
64586
64609
  };
64587
64610
  }));
64588
64611
  shapeSelect.value = orig_shape;
@@ -64593,25 +64616,25 @@ function show_port_popover(gobj) {
64593
64616
  let scopeSelect = create_form_select(popover, [
64594
64617
  {
64595
64618
  value: "this",
64596
- label: (0, i18next.t)("this port")
64619
+ i18n: "this port"
64597
64620
  },
64598
64621
  {
64599
64622
  value: "same_topic",
64600
- label: (0, i18next.t)("same port in topic")
64623
+ i18n: "same port in topic"
64601
64624
  },
64602
64625
  {
64603
64626
  value: "all",
64604
- label: (0, i18next.t)("all ports")
64627
+ i18n: "all ports"
64605
64628
  }
64606
64629
  ]);
64607
64630
  create_form_button_row(popover, [{
64608
- text: "cancel",
64631
+ i18n: "cancel",
64609
64632
  style: BTN_STYLE_CANCEL,
64610
64633
  onClick: () => {
64611
64634
  hide_port_popover(gobj);
64612
64635
  }
64613
64636
  }, {
64614
- text: "apply",
64637
+ i18n: "apply",
64615
64638
  style: "flex:1;padding:6px;background:#1890ff;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
64616
64639
  onClick: () => {
64617
64640
  drop_preview_undo(gobj, "_port_preview_undo");
@@ -65289,25 +65312,25 @@ function show_edge_popover(gobj) {
65289
65312
  let scopeSelect = create_form_select(popover, [
65290
65313
  {
65291
65314
  value: "this",
65292
- label: (0, i18next.t)("this edge")
65315
+ i18n: "this edge"
65293
65316
  },
65294
65317
  {
65295
65318
  value: "same_type",
65296
- label: (0, i18next.t)("same type edges")
65319
+ i18n: "same type edges"
65297
65320
  },
65298
65321
  {
65299
65322
  value: "all",
65300
- label: (0, i18next.t)("all edges")
65323
+ i18n: "all edges"
65301
65324
  }
65302
65325
  ]);
65303
65326
  create_form_button_row(popover, [{
65304
- text: "cancel",
65327
+ i18n: "cancel",
65305
65328
  style: BTN_STYLE_CANCEL,
65306
65329
  onClick: () => {
65307
65330
  deselect_edge(gobj);
65308
65331
  }
65309
65332
  }, {
65310
- text: "apply",
65333
+ i18n: "apply",
65311
65334
  style: "flex:1;padding:6px;background:#52c41a;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
65312
65335
  onClick: () => {
65313
65336
  drop_preview_undo(gobj, "_edge_preview_undo");
@@ -65441,7 +65464,7 @@ function show_node_popover(gobj) {
65441
65464
  let shapeSelect = create_form_select(popover, NODE_SHAPES.map((shape) => {
65442
65465
  return {
65443
65466
  value: shape,
65444
- label: (0, i18next.t)(shape)
65467
+ i18n: shape
65445
65468
  };
65446
65469
  }));
65447
65470
  shapeSelect.value = nodeData.data && nodeData.data.desc ? node_figure_of(gobj, nodeData.data.desc, nodeData.data.graph_props || {}) : DEFAULT_NODE_SHAPE;
@@ -65450,25 +65473,25 @@ function show_node_popover(gobj) {
65450
65473
  let scopeSelect = create_form_select(popover, [
65451
65474
  {
65452
65475
  value: "this",
65453
- label: (0, i18next.t)("this node")
65476
+ i18n: "this node"
65454
65477
  },
65455
65478
  {
65456
65479
  value: "same_topic",
65457
- label: (0, i18next.t)("same topic nodes")
65480
+ i18n: "same topic nodes"
65458
65481
  },
65459
65482
  {
65460
65483
  value: "all",
65461
- label: (0, i18next.t)("all nodes")
65484
+ i18n: "all nodes"
65462
65485
  }
65463
65486
  ]);
65464
65487
  create_form_button_row(popover, [{
65465
- text: "cancel",
65488
+ i18n: "cancel",
65466
65489
  style: BTN_STYLE_CANCEL,
65467
65490
  onClick: () => {
65468
65491
  hide_node_popover(gobj);
65469
65492
  }
65470
65493
  }, {
65471
- text: "apply",
65494
+ i18n: "apply",
65472
65495
  style: "flex:1;padding:6px;background:#1890ff;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
65473
65496
  onClick: () => {
65474
65497
  drop_preview_undo(gobj, "_node_preview_undo");
@@ -66122,12 +66145,21 @@ function show_create_popover(gobj) {
66122
66145
  let titleEl = document.createElement("div");
66123
66146
  titleEl.style.cssText = "margin-bottom:10px;font-weight:600;font-size:14px;";
66124
66147
  titleEl.textContent = (0, i18next.t)("create node");
66148
+ titleEl.setAttribute("data-i18n", "create node");
66125
66149
  popover.appendChild(titleEl);
66126
66150
  let topicLabel = document.createElement("div");
66127
66151
  topicLabel.style.cssText = "margin-bottom:4px;font-weight:500;";
66128
- topicLabel.textContent = (0, i18next.t)("topic") + ":";
66152
+ let topicWord = document.createElement("span");
66153
+ topicWord.textContent = (0, i18next.t)("topic");
66154
+ topicWord.setAttribute("data-i18n", "topic");
66155
+ topicLabel.appendChild(topicWord);
66156
+ topicLabel.appendChild(document.createTextNode(":"));
66129
66157
  popover.appendChild(topicLabel);
66130
66158
  let topicSelect = document.createElement("select");
66159
+ topicSelect.setAttribute("title", (0, i18next.t)("topic"));
66160
+ topicSelect.setAttribute("data-i18n-title", "topic");
66161
+ topicSelect.setAttribute("aria-label", (0, i18next.t)("topic"));
66162
+ topicSelect.setAttribute("data-i18n-aria-label", "topic");
66131
66163
  topicSelect.style.cssText = "width:100%;padding:6px;border:1px solid #d9d9d9;border-radius:4px;font-size:13px;margin-bottom:8px;" + touch_control_css();
66132
66164
  for (let i = 0; i < topics.length; i++) {
66133
66165
  let opt = document.createElement("option");
@@ -66156,11 +66188,20 @@ function show_create_popover(gobj) {
66156
66188
  });
66157
66189
  let idLabel = document.createElement("div");
66158
66190
  idLabel.style.cssText = "margin-bottom:4px;font-weight:500;";
66159
- idLabel.textContent = "Id:";
66191
+ let idWord = document.createElement("span");
66192
+ idWord.textContent = (0, i18next.t)("node id");
66193
+ idWord.setAttribute("data-i18n", "node id");
66194
+ idLabel.appendChild(idWord);
66195
+ idLabel.appendChild(document.createTextNode(":"));
66160
66196
  popover.appendChild(idLabel);
66161
66197
  let idInput = document.createElement("input");
66162
66198
  idInput.type = "text";
66163
66199
  idInput.placeholder = (0, i18next.t)("node id");
66200
+ idInput.setAttribute("data-i18n-placeholder", "node id");
66201
+ idInput.setAttribute("title", (0, i18next.t)("node id"));
66202
+ idInput.setAttribute("data-i18n-title", "node id");
66203
+ idInput.setAttribute("aria-label", (0, i18next.t)("node id"));
66204
+ idInput.setAttribute("data-i18n-aria-label", "node id");
66164
66205
  idInput.style.cssText = "width:100%;padding:6px;border:1px solid #d9d9d9;border-radius:4px;font-size:13px;margin-bottom:10px;box-sizing:border-box;" + touch_control_css();
66165
66206
  popover.appendChild(idInput);
66166
66207
  let errorEl = document.createElement("div");
@@ -66168,16 +66209,17 @@ function show_create_popover(gobj) {
66168
66209
  popover.appendChild(errorEl);
66169
66210
  let createBtn;
66170
66211
  create_form_button_row(popover, [{
66171
- text: "cancel",
66212
+ i18n: "cancel",
66172
66213
  style: BTN_STYLE_CANCEL,
66173
66214
  onClick: () => hide_create_popover(gobj)
66174
66215
  }, {
66175
- text: "create",
66216
+ i18n: "create",
66176
66217
  style: "flex:1;padding:6px;background:#1890ff;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
66177
66218
  onClick: () => {
66178
66219
  let node_id = idInput.value.trim();
66179
66220
  if (!node_id) {
66180
- errorEl.textContent = (0, i18next.t)("node id") + " required";
66221
+ errorEl.textContent = (0, i18next.t)("node id required");
66222
+ errorEl.setAttribute("data-i18n", "node id required");
66181
66223
  errorEl.style.display = "block";
66182
66224
  idInput.focus();
66183
66225
  return;
@@ -7176,11 +7176,11 @@ function yui_file_control(gobj, { name, value, readonly, accept, on_pick }) {
7176
7176
  if (picked) {
7177
7177
  $state.classList.add("is-picked");
7178
7178
  $state.setAttribute("data-i18n", "not saved yet");
7179
- $state.textContent = "not saved yet";
7179
+ $state.textContent = t("not saved yet");
7180
7180
  } else if (!kept) {
7181
7181
  $state.classList.add("is-empty");
7182
7182
  $state.setAttribute("data-i18n", "no file");
7183
- $state.textContent = "no file";
7183
+ $state.textContent = t("no file");
7184
7184
  }
7185
7185
  $clear.hidden = readonly || !picked && !kept;
7186
7186
  $pick.hidden = !!readonly;
@@ -8983,7 +8983,7 @@ function destroy_widgets(gobj, $container) {
8983
8983
  * ids would break the association for both. The key is the
8984
8984
  * label's own, so a language change reaches it.
8985
8985
  ************************************************************/
8986
- function name_form_control($field, conf) {
8986
+ function name_form_control$1($field, conf) {
8987
8987
  if (!$field || typeof $field.querySelector !== "function" || !conf) return;
8988
8988
  let key = conf.label_i18n || conf.label || "";
8989
8989
  if (!key) return;
@@ -9054,7 +9054,7 @@ function build_html_form(gobj, $form, prefix, template) {
9054
9054
  if (placeholders[key]) html_field_conf.placeholder = placeholders[key];
9055
9055
  if (html_field_conf.tag) {
9056
9056
  let $field = create_form_field(gobj, $form, prefix, field_desc, html_field_conf);
9057
- name_form_control($field, html_field_conf);
9057
+ name_form_control$1($field, html_field_conf);
9058
9058
  $form.appendChild($field);
9059
9059
  }
9060
9060
  });
@@ -63788,19 +63788,34 @@ function touch_control_css() {
63788
63788
  if (!coarse_pointer()) return "";
63789
63789
  return "min-height:44px;font-size:16px;";
63790
63790
  }
63791
+ var form_control_seq = 0;
63791
63792
  function create_form_label(parent, text) {
63792
63793
  let label = document.createElement("label");
63793
63794
  label.textContent = t(text);
63795
+ label.setAttribute("data-i18n", text);
63794
63796
  label.style.cssText = "display:block;margin-bottom:4px;font-weight:500;";
63795
63797
  parent.appendChild(label);
63796
63798
  return label;
63797
63799
  }
63800
+ function name_form_control(parent, control) {
63801
+ let label = parent.lastElementChild;
63802
+ if (!label || label.tagName !== "LABEL") return;
63803
+ let key = label.getAttribute("data-i18n");
63804
+ if (!key) return;
63805
+ control.id = "g6-form-control-" + ++form_control_seq;
63806
+ label.htmlFor = control.id;
63807
+ control.setAttribute("title", t(key));
63808
+ control.setAttribute("data-i18n-title", key);
63809
+ control.setAttribute("aria-label", t(key));
63810
+ control.setAttribute("data-i18n-aria-label", key);
63811
+ }
63798
63812
  function create_form_color_input(parent, value, onInput) {
63799
63813
  let input = document.createElement("input");
63800
63814
  input.type = "color";
63801
63815
  input.value = value;
63802
63816
  input.style.cssText = "width:100%;height:30px;padding:0;border:1px solid var(--bulma-border-weak, #d9d9d9);border-radius:4px;cursor:pointer;margin-bottom:10px;" + touch_control_css();
63803
63817
  if (onInput) input.addEventListener("input", onInput);
63818
+ name_form_control(parent, input);
63804
63819
  parent.appendChild(input);
63805
63820
  return input;
63806
63821
  }
@@ -63812,6 +63827,7 @@ function create_form_number_input(parent, value, min, max, onInput) {
63812
63827
  input.value = value;
63813
63828
  input.style.cssText = "width:100%;padding:4px 6px;background:var(--bulma-scheme-main-bis, #fff);color:var(--bulma-text-strong, #333);border:1px solid var(--bulma-border-weak, #d9d9d9);border-radius:4px;box-sizing:border-box;margin-bottom:10px;" + touch_control_css();
63814
63829
  if (onInput) input.addEventListener("input", onInput);
63830
+ name_form_control(parent, input);
63815
63831
  parent.appendChild(input);
63816
63832
  return input;
63817
63833
  }
@@ -63821,9 +63837,11 @@ function create_form_select(parent, options, marginBottom) {
63821
63837
  for (let opt of options) {
63822
63838
  let o = document.createElement("option");
63823
63839
  o.value = opt.value;
63824
- o.textContent = opt.label;
63840
+ o.textContent = t(opt.i18n);
63841
+ o.setAttribute("data-i18n", opt.i18n);
63825
63842
  select.appendChild(o);
63826
63843
  }
63844
+ name_form_control(parent, select);
63827
63845
  parent.appendChild(select);
63828
63846
  return select;
63829
63847
  }
@@ -63831,9 +63849,14 @@ var BTN_STYLE_CANCEL = "flex:1;padding:6px;background:var(--bulma-scheme-main-bi
63831
63849
  function create_form_button_row(parent, buttons) {
63832
63850
  let btnRow = document.createElement("div");
63833
63851
  btnRow.style.cssText = "display:flex;gap:8px;";
63834
- for (let { text, style, onClick } of buttons) {
63852
+ for (let { i18n, style, onClick } of buttons) {
63835
63853
  let btn = document.createElement("button");
63836
- btn.textContent = t(text);
63854
+ btn.textContent = t(i18n);
63855
+ btn.setAttribute("data-i18n", i18n);
63856
+ btn.setAttribute("title", t(i18n));
63857
+ btn.setAttribute("data-i18n-title", i18n);
63858
+ btn.setAttribute("aria-label", t(i18n));
63859
+ btn.setAttribute("data-i18n-aria-label", i18n);
63837
63860
  btn.style.cssText = style + touch_control_css();
63838
63861
  btn.addEventListener("click", (e) => {
63839
63862
  e.stopPropagation();
@@ -63867,11 +63890,11 @@ function show_confirm_popover(gobj, target_el, message, confirm_text, confirm_co
63867
63890
  msg.textContent = message;
63868
63891
  popover.appendChild(msg);
63869
63892
  create_form_button_row(popover, [{
63870
- text: "cancel",
63893
+ i18n: "cancel",
63871
63894
  style: BTN_STYLE_CANCEL,
63872
63895
  onClick: () => hide_overlay(gobj, priv_key)
63873
63896
  }, {
63874
- text: confirm_text,
63897
+ i18n: confirm_text,
63875
63898
  style: "flex:1;padding:6px;background:" + confirm_color + ";color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
63876
63899
  onClick: onConfirm
63877
63900
  }]);
@@ -64577,7 +64600,7 @@ function show_port_popover(gobj) {
64577
64600
  let shapeSelect = create_form_select(popover, PORT_SHAPES.map((shape) => {
64578
64601
  return {
64579
64602
  value: shape,
64580
- label: t(shape)
64603
+ i18n: shape
64581
64604
  };
64582
64605
  }));
64583
64606
  shapeSelect.value = orig_shape;
@@ -64588,25 +64611,25 @@ function show_port_popover(gobj) {
64588
64611
  let scopeSelect = create_form_select(popover, [
64589
64612
  {
64590
64613
  value: "this",
64591
- label: t("this port")
64614
+ i18n: "this port"
64592
64615
  },
64593
64616
  {
64594
64617
  value: "same_topic",
64595
- label: t("same port in topic")
64618
+ i18n: "same port in topic"
64596
64619
  },
64597
64620
  {
64598
64621
  value: "all",
64599
- label: t("all ports")
64622
+ i18n: "all ports"
64600
64623
  }
64601
64624
  ]);
64602
64625
  create_form_button_row(popover, [{
64603
- text: "cancel",
64626
+ i18n: "cancel",
64604
64627
  style: BTN_STYLE_CANCEL,
64605
64628
  onClick: () => {
64606
64629
  hide_port_popover(gobj);
64607
64630
  }
64608
64631
  }, {
64609
- text: "apply",
64632
+ i18n: "apply",
64610
64633
  style: "flex:1;padding:6px;background:#1890ff;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
64611
64634
  onClick: () => {
64612
64635
  drop_preview_undo(gobj, "_port_preview_undo");
@@ -65284,25 +65307,25 @@ function show_edge_popover(gobj) {
65284
65307
  let scopeSelect = create_form_select(popover, [
65285
65308
  {
65286
65309
  value: "this",
65287
- label: t("this edge")
65310
+ i18n: "this edge"
65288
65311
  },
65289
65312
  {
65290
65313
  value: "same_type",
65291
- label: t("same type edges")
65314
+ i18n: "same type edges"
65292
65315
  },
65293
65316
  {
65294
65317
  value: "all",
65295
- label: t("all edges")
65318
+ i18n: "all edges"
65296
65319
  }
65297
65320
  ]);
65298
65321
  create_form_button_row(popover, [{
65299
- text: "cancel",
65322
+ i18n: "cancel",
65300
65323
  style: BTN_STYLE_CANCEL,
65301
65324
  onClick: () => {
65302
65325
  deselect_edge(gobj);
65303
65326
  }
65304
65327
  }, {
65305
- text: "apply",
65328
+ i18n: "apply",
65306
65329
  style: "flex:1;padding:6px;background:#52c41a;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
65307
65330
  onClick: () => {
65308
65331
  drop_preview_undo(gobj, "_edge_preview_undo");
@@ -65436,7 +65459,7 @@ function show_node_popover(gobj) {
65436
65459
  let shapeSelect = create_form_select(popover, NODE_SHAPES.map((shape) => {
65437
65460
  return {
65438
65461
  value: shape,
65439
- label: t(shape)
65462
+ i18n: shape
65440
65463
  };
65441
65464
  }));
65442
65465
  shapeSelect.value = nodeData.data && nodeData.data.desc ? node_figure_of(gobj, nodeData.data.desc, nodeData.data.graph_props || {}) : DEFAULT_NODE_SHAPE;
@@ -65445,25 +65468,25 @@ function show_node_popover(gobj) {
65445
65468
  let scopeSelect = create_form_select(popover, [
65446
65469
  {
65447
65470
  value: "this",
65448
- label: t("this node")
65471
+ i18n: "this node"
65449
65472
  },
65450
65473
  {
65451
65474
  value: "same_topic",
65452
- label: t("same topic nodes")
65475
+ i18n: "same topic nodes"
65453
65476
  },
65454
65477
  {
65455
65478
  value: "all",
65456
- label: t("all nodes")
65479
+ i18n: "all nodes"
65457
65480
  }
65458
65481
  ]);
65459
65482
  create_form_button_row(popover, [{
65460
- text: "cancel",
65483
+ i18n: "cancel",
65461
65484
  style: BTN_STYLE_CANCEL,
65462
65485
  onClick: () => {
65463
65486
  hide_node_popover(gobj);
65464
65487
  }
65465
65488
  }, {
65466
- text: "apply",
65489
+ i18n: "apply",
65467
65490
  style: "flex:1;padding:6px;background:#1890ff;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
65468
65491
  onClick: () => {
65469
65492
  drop_preview_undo(gobj, "_node_preview_undo");
@@ -66117,12 +66140,21 @@ function show_create_popover(gobj) {
66117
66140
  let titleEl = document.createElement("div");
66118
66141
  titleEl.style.cssText = "margin-bottom:10px;font-weight:600;font-size:14px;";
66119
66142
  titleEl.textContent = t("create node");
66143
+ titleEl.setAttribute("data-i18n", "create node");
66120
66144
  popover.appendChild(titleEl);
66121
66145
  let topicLabel = document.createElement("div");
66122
66146
  topicLabel.style.cssText = "margin-bottom:4px;font-weight:500;";
66123
- topicLabel.textContent = t("topic") + ":";
66147
+ let topicWord = document.createElement("span");
66148
+ topicWord.textContent = t("topic");
66149
+ topicWord.setAttribute("data-i18n", "topic");
66150
+ topicLabel.appendChild(topicWord);
66151
+ topicLabel.appendChild(document.createTextNode(":"));
66124
66152
  popover.appendChild(topicLabel);
66125
66153
  let topicSelect = document.createElement("select");
66154
+ topicSelect.setAttribute("title", t("topic"));
66155
+ topicSelect.setAttribute("data-i18n-title", "topic");
66156
+ topicSelect.setAttribute("aria-label", t("topic"));
66157
+ topicSelect.setAttribute("data-i18n-aria-label", "topic");
66126
66158
  topicSelect.style.cssText = "width:100%;padding:6px;border:1px solid #d9d9d9;border-radius:4px;font-size:13px;margin-bottom:8px;" + touch_control_css();
66127
66159
  for (let i = 0; i < topics.length; i++) {
66128
66160
  let opt = document.createElement("option");
@@ -66151,11 +66183,20 @@ function show_create_popover(gobj) {
66151
66183
  });
66152
66184
  let idLabel = document.createElement("div");
66153
66185
  idLabel.style.cssText = "margin-bottom:4px;font-weight:500;";
66154
- idLabel.textContent = "Id:";
66186
+ let idWord = document.createElement("span");
66187
+ idWord.textContent = t("node id");
66188
+ idWord.setAttribute("data-i18n", "node id");
66189
+ idLabel.appendChild(idWord);
66190
+ idLabel.appendChild(document.createTextNode(":"));
66155
66191
  popover.appendChild(idLabel);
66156
66192
  let idInput = document.createElement("input");
66157
66193
  idInput.type = "text";
66158
66194
  idInput.placeholder = t("node id");
66195
+ idInput.setAttribute("data-i18n-placeholder", "node id");
66196
+ idInput.setAttribute("title", t("node id"));
66197
+ idInput.setAttribute("data-i18n-title", "node id");
66198
+ idInput.setAttribute("aria-label", t("node id"));
66199
+ idInput.setAttribute("data-i18n-aria-label", "node id");
66159
66200
  idInput.style.cssText = "width:100%;padding:6px;border:1px solid #d9d9d9;border-radius:4px;font-size:13px;margin-bottom:10px;box-sizing:border-box;" + touch_control_css();
66160
66201
  popover.appendChild(idInput);
66161
66202
  let errorEl = document.createElement("div");
@@ -66163,16 +66204,17 @@ function show_create_popover(gobj) {
66163
66204
  popover.appendChild(errorEl);
66164
66205
  let createBtn;
66165
66206
  create_form_button_row(popover, [{
66166
- text: "cancel",
66207
+ i18n: "cancel",
66167
66208
  style: BTN_STYLE_CANCEL,
66168
66209
  onClick: () => hide_create_popover(gobj)
66169
66210
  }, {
66170
- text: "create",
66211
+ i18n: "create",
66171
66212
  style: "flex:1;padding:6px;background:#1890ff;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
66172
66213
  onClick: () => {
66173
66214
  let node_id = idInput.value.trim();
66174
66215
  if (!node_id) {
66175
- errorEl.textContent = t("node id") + " required";
66216
+ errorEl.textContent = t("node id required");
66217
+ errorEl.setAttribute("data-i18n", "node id required");
66176
66218
  errorEl.style.display = "block";
66177
66219
  idInput.focus();
66178
66220
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.26.25",
3
+ "version": "7.26.27",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",