@yuneta/gobj-ui 5.3.3 → 5.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +114 -1
- package/dist/gobj-ui.cjs.js +475 -212
- package/dist/gobj-ui.es.js +473 -213
- package/index.js +5 -0
- package/package.json +44 -44
- package/src/c_yui_node.js +142 -6
- package/src/c_yui_service_view.js +362 -0
- package/src/c_yui_shell.js +42 -14
- package/src/node_tree_model.js +67 -0
- package/src/node_tree_model.test.js +70 -0
package/index.js
CHANGED
|
@@ -24,6 +24,11 @@ export { register_c_yui_uplot } from "./src/c_yui_uplot.js";
|
|
|
24
24
|
export { register_c_yui_json_graph } from "./src/c_yui_json_graph.js";
|
|
25
25
|
export { register_c_yui_json } from "./src/c_yui_json.js";
|
|
26
26
|
export { register_c_yui_gobj_tree_js } from "./src/c_yui_gobj_tree_js.js";
|
|
27
|
+
export {
|
|
28
|
+
register_c_yui_service_view,
|
|
29
|
+
yui_mount_service_view,
|
|
30
|
+
expose_view_container,
|
|
31
|
+
} from "./src/c_yui_service_view.js";
|
|
27
32
|
|
|
28
33
|
/*
|
|
29
34
|
* Declarative shell + menu navigation (new in v7.4)
|
package/package.json
CHANGED
|
@@ -1,47 +1,47 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
},
|
|
12
|
-
"./index.js": "./index.js",
|
|
13
|
-
"./vite-plugin-yuneta-html.js": "./vite-plugin-yuneta-html.js",
|
|
14
|
-
"./src/*": "./src/*"
|
|
2
|
+
"name": "@yuneta/gobj-ui",
|
|
3
|
+
"version": "5.5.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/gobj-ui.cjs.js",
|
|
6
|
+
"module": "dist/gobj-ui.es.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/gobj-ui.es.js",
|
|
10
|
+
"require": "./dist/gobj-ui.cjs.js"
|
|
15
11
|
},
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
12
|
+
"./index.js": "./index.js",
|
|
13
|
+
"./vite-plugin-yuneta-html.js": "./vite-plugin-yuneta-html.js",
|
|
14
|
+
"./src/*": "./src/*"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist/gobj-ui.es.js",
|
|
18
|
+
"dist/gobj-ui.cjs.js",
|
|
19
|
+
"index.js",
|
|
20
|
+
"src/",
|
|
21
|
+
"vite-plugin-yuneta-html.js"
|
|
22
|
+
],
|
|
23
|
+
"description": "Yuneta UI Library — the active line: declarative shell (C_YUI_SHELL+NAV+PAGER+WIZARD) + windows, TreeDB views, forms, charts and maps. Consumed by wattyzer and the yunetas JS yunos (gui_agent, gui_treedb). The frozen legacy GClass GUI stack (C_YUI_MAIN/TABS/ROUTING) lives on the v1 branch, npm dist-tag 'legacy' (consumed by estadodelaire and hidraulia).",
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "vite build",
|
|
26
|
+
"test": "vitest run",
|
|
27
|
+
"prepublishOnly": "npm run build"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@rollup/plugin-terser": "^1.0.0",
|
|
31
|
+
"@vitest/coverage-v8": "^4.1.10",
|
|
32
|
+
"@yuneta/gobj-js": "^7.8.7",
|
|
33
|
+
"vite": "^8.1.5",
|
|
34
|
+
"vitest": "^4.1.10"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"@antv/g6": "^5.1.0",
|
|
38
|
+
"@yuneta/gobj-js": "^7.8.7",
|
|
39
|
+
"bulma": "^1.0.4",
|
|
40
|
+
"i18next": "^26.3.6",
|
|
41
|
+
"maplibre-gl": "^6.0.0",
|
|
42
|
+
"tabulator-tables": "^6.5.2",
|
|
43
|
+
"tom-select": "^2.6.2",
|
|
44
|
+
"uplot": "^1.6.32",
|
|
45
|
+
"vanilla-jsoneditor": "^3.13.0"
|
|
46
|
+
}
|
|
47
47
|
}
|
package/src/c_yui_node.js
CHANGED
|
@@ -126,6 +126,10 @@ import {
|
|
|
126
126
|
child_nav_items,
|
|
127
127
|
chrome_visible,
|
|
128
128
|
normalize_spec,
|
|
129
|
+
is_nav_mode,
|
|
130
|
+
nav_mode_renders,
|
|
131
|
+
nav_mode_depth,
|
|
132
|
+
NAV_MODES,
|
|
129
133
|
} from "./node_tree_model.js";
|
|
130
134
|
|
|
131
135
|
import {
|
|
@@ -133,6 +137,7 @@ import {
|
|
|
133
137
|
yui_shell_zone,
|
|
134
138
|
yui_shell_navigate,
|
|
135
139
|
yui_shell_set_sub_routes,
|
|
140
|
+
yui_shell_translate,
|
|
136
141
|
} from "./c_yui_shell.js";
|
|
137
142
|
|
|
138
143
|
import "./c_yui_node.css";
|
|
@@ -169,6 +174,7 @@ SDATA(data_type_t.DTP_JSON, "children", 0, null, "Declared child spec
|
|
|
169
174
|
|
|
170
175
|
SDATA(data_type_t.DTP_STRING, "base_route", 0, "", "ROOT only: the declared route the whole tree hangs from"),
|
|
171
176
|
SDATA(data_type_t.DTP_STRING, "tree_version", 0, "", "ROOT only: version of the tree CONTRACT (its paths are public urls)"),
|
|
177
|
+
SDATA(data_type_t.DTP_STRING, "nav_mode", 0, "stack","ROOT only: how the way in is shown — stack|back|path"),
|
|
172
178
|
|
|
173
179
|
SDATA(data_type_t.DTP_POINTER, "$container", 0, null, "Root HTMLElement (shell view contract)"),
|
|
174
180
|
SDATA_END()
|
|
@@ -389,6 +395,29 @@ function tree_root_of(gobj)
|
|
|
389
395
|
}
|
|
390
396
|
}
|
|
391
397
|
|
|
398
|
+
/************************************************************
|
|
399
|
+
* The navigation mode in force for this node.
|
|
400
|
+
*
|
|
401
|
+
* It is ONE knob per tree, held by the root: a tree whose ancestors
|
|
402
|
+
* stacked strips while a descendant drew a breadcrumb would be
|
|
403
|
+
* showing the way in twice, in two languages. Descendants read it
|
|
404
|
+
* from the root rather than keeping a copy, so a node added at
|
|
405
|
+
* runtime is born in the mode the tree is already in.
|
|
406
|
+
************************************************************/
|
|
407
|
+
function nav_mode_of(gobj)
|
|
408
|
+
{
|
|
409
|
+
let mode = gobj_read_attr(tree_root_of(gobj), "nav_mode") || "stack";
|
|
410
|
+
|
|
411
|
+
if(!is_nav_mode(mode)) {
|
|
412
|
+
log_error(
|
|
413
|
+
`${GCLASS_NAME} '${node_path_str(gobj)}': unknown nav_mode ` +
|
|
414
|
+
`'${mode}' — expected one of ${NAV_MODES.join("|")}`
|
|
415
|
+
);
|
|
416
|
+
return "stack";
|
|
417
|
+
}
|
|
418
|
+
return mode;
|
|
419
|
+
}
|
|
420
|
+
|
|
392
421
|
/************************************************************
|
|
393
422
|
* Node ids from the root DOWN TO this node, root excluded
|
|
394
423
|
* (the root's own segment is already inside base_route).
|
|
@@ -494,12 +523,14 @@ function resolve_path_info(gobj, subpath, inherited)
|
|
|
494
523
|
{
|
|
495
524
|
let effective = (typeof inherited === "number") ? inherited : null;
|
|
496
525
|
|
|
526
|
+
let mode = nav_mode_of(gobj);
|
|
527
|
+
|
|
497
528
|
let own = gobj_read_attr(gobj, "chrome_depth");
|
|
498
529
|
if(typeof own === "number" && own >= 0) {
|
|
499
530
|
effective = own;
|
|
500
531
|
}
|
|
501
532
|
if(has_link(gobj)) {
|
|
502
|
-
return {distance: 0, chrome_depth: effective, chain: []};
|
|
533
|
+
return {distance: 0, chrome_depth: nav_mode_depth(effective, mode), chain: []};
|
|
503
534
|
}
|
|
504
535
|
|
|
505
536
|
/* Distance is counted in STRUCTURAL segments: the tail a viewer
|
|
@@ -524,7 +555,11 @@ function resolve_path_info(gobj, subpath, inherited)
|
|
|
524
555
|
break;
|
|
525
556
|
}
|
|
526
557
|
}
|
|
527
|
-
return {
|
|
558
|
+
return {
|
|
559
|
+
distance: distance,
|
|
560
|
+
chrome_depth: nav_mode_depth(effective, mode),
|
|
561
|
+
chain: chain
|
|
562
|
+
};
|
|
528
563
|
}
|
|
529
564
|
|
|
530
565
|
/************************************************************
|
|
@@ -548,6 +583,30 @@ function walk_path(node, path)
|
|
|
548
583
|
return {node: g, missing: segs.slice(i)};
|
|
549
584
|
}
|
|
550
585
|
|
|
586
|
+
/************************************************************
|
|
587
|
+
* Translate a subtree this node just built.
|
|
588
|
+
*
|
|
589
|
+
* A node renders its chrome WHEN YOU WALK INTO IT, long after
|
|
590
|
+
* the host's one-shot refresh_language over the shell tree, and
|
|
591
|
+
* its zone navs are appended into shell zones, outside this
|
|
592
|
+
* node's own $container. Neither pass reaches them, so without
|
|
593
|
+
* this every strip renders its raw i18n key: `treedb`,
|
|
594
|
+
* `central database`, `data` in lower-case English next to a
|
|
595
|
+
* translated menu — which reads as a MISSING key and sent more
|
|
596
|
+
* than one person looking for the wrong bug.
|
|
597
|
+
*
|
|
598
|
+
* This is library-built DOM, so it goes through the shell's
|
|
599
|
+
* registered translator. What a node MOUNTS is not ours: an app
|
|
600
|
+
* view gclass translates its own DOM.
|
|
601
|
+
************************************************************/
|
|
602
|
+
function translate_own_dom(gobj, $el)
|
|
603
|
+
{
|
|
604
|
+
if(!$el) {
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
yui_shell_translate(yui_shell_of(gobj), $el);
|
|
608
|
+
}
|
|
609
|
+
|
|
551
610
|
/************************************************************
|
|
552
611
|
* Destroy the C_YUI_NAV gobjs rendering this node's projection.
|
|
553
612
|
************************************************************/
|
|
@@ -575,7 +634,8 @@ function render_projection(gobj, mode, $where, active_route, active_id, zones_on
|
|
|
575
634
|
if(!priv.children.length) {
|
|
576
635
|
return;
|
|
577
636
|
}
|
|
578
|
-
let renders =
|
|
637
|
+
let renders = nav_mode_renders(gobj_read_attr(gobj, "projection"),
|
|
638
|
+
nav_mode_of(gobj), mode, priv.is_root);
|
|
579
639
|
if(!renders.length) {
|
|
580
640
|
return;
|
|
581
641
|
}
|
|
@@ -634,6 +694,7 @@ function render_projection(gobj, mode, $where, active_route, active_id, zones_on
|
|
|
634
694
|
let $nav = gobj_read_attr(nav, "$container");
|
|
635
695
|
if($nav) {
|
|
636
696
|
$target.appendChild($nav);
|
|
697
|
+
translate_own_dom(gobj, $nav);
|
|
637
698
|
}
|
|
638
699
|
priv.navs.push(nav);
|
|
639
700
|
i++;
|
|
@@ -681,11 +742,14 @@ function project_into_zone(gobj, render, items, active_route, active_id)
|
|
|
681
742
|
let $nav = gobj_read_attr(nav, "$container");
|
|
682
743
|
if($nav) {
|
|
683
744
|
$zone.appendChild($nav);
|
|
745
|
+
translate_own_dom(gobj, $nav);
|
|
684
746
|
}
|
|
685
747
|
priv.zone_navs[key] = nav;
|
|
686
748
|
priv.zone_sig[key] = sig;
|
|
687
749
|
} else if(priv.zone_sig[key] !== sig) {
|
|
688
750
|
gobj_send_event(nav, "EV_SET_ITEMS", {items: items}, gobj);
|
|
751
|
+
/* EV_SET_ITEMS rebuilt the nav's DOM: translate it again. */
|
|
752
|
+
translate_own_dom(gobj, gobj_read_attr(nav, "$container"));
|
|
689
753
|
priv.zone_sig[key] = sig;
|
|
690
754
|
}
|
|
691
755
|
|
|
@@ -786,10 +850,12 @@ function render_self(gobj)
|
|
|
786
850
|
}
|
|
787
851
|
|
|
788
852
|
if(!view) {
|
|
789
|
-
|
|
853
|
+
let $empty = createElement2(
|
|
790
854
|
["div", {class: "NODE_EMPTY", i18n: "nothing here yet"},
|
|
791
855
|
"Nothing here yet."]
|
|
792
|
-
)
|
|
856
|
+
);
|
|
857
|
+
priv.$body.appendChild($empty);
|
|
858
|
+
translate_own_dom(gobj, $empty);
|
|
793
859
|
}
|
|
794
860
|
}
|
|
795
861
|
|
|
@@ -833,7 +899,8 @@ function render_child(gobj, child)
|
|
|
833
899
|
function render_path(gobj, $where)
|
|
834
900
|
{
|
|
835
901
|
let priv = gobj.priv;
|
|
836
|
-
let renders =
|
|
902
|
+
let renders = nav_mode_renders(gobj_read_attr(gobj, "projection"),
|
|
903
|
+
nav_mode_of(gobj), "path", priv.is_root);
|
|
837
904
|
|
|
838
905
|
if(!renders.length) {
|
|
839
906
|
return;
|
|
@@ -881,6 +948,7 @@ function render_path(gobj, $where)
|
|
|
881
948
|
let $nav = gobj_read_attr(nav, "$container");
|
|
882
949
|
if($nav) {
|
|
883
950
|
$where.appendChild($nav);
|
|
951
|
+
translate_own_dom(gobj, $nav);
|
|
884
952
|
}
|
|
885
953
|
priv.navs.push(nav);
|
|
886
954
|
i++;
|
|
@@ -1328,6 +1396,54 @@ function ac_set_chrome_depth(gobj, event, kw, src)
|
|
|
1328
1396
|
return 0;
|
|
1329
1397
|
}
|
|
1330
1398
|
|
|
1399
|
+
/************************************************************
|
|
1400
|
+
* Runtime API: change how this TREE shows the way in.
|
|
1401
|
+
*
|
|
1402
|
+
* One knob for the whole tree, and deliberately root-only: the
|
|
1403
|
+
* mode answers "how deep am I and how do I get back", a question
|
|
1404
|
+
* that has one answer per tree. Set on a middle node it would
|
|
1405
|
+
* silently do nothing (descendants read the root's), and a knob
|
|
1406
|
+
* that accepts a call and ignores it is worse than one that
|
|
1407
|
+
* refuses it.
|
|
1408
|
+
*
|
|
1409
|
+
* Nothing declared is rewritten — the mode filters the renders as
|
|
1410
|
+
* they are asked for — so going back to "stack" restores exactly
|
|
1411
|
+
* what the app declared, per branch, including layouts this mode
|
|
1412
|
+
* never mentions.
|
|
1413
|
+
************************************************************/
|
|
1414
|
+
function ac_set_nav_mode(gobj, event, kw, src)
|
|
1415
|
+
{
|
|
1416
|
+
let priv = gobj.priv;
|
|
1417
|
+
let mode = kw.nav_mode || "";
|
|
1418
|
+
|
|
1419
|
+
if(!is_nav_mode(mode)) {
|
|
1420
|
+
log_error(
|
|
1421
|
+
`${GCLASS_NAME} '${node_path_str(gobj)}': unknown nav_mode ` +
|
|
1422
|
+
`'${mode}' — expected one of ${NAV_MODES.join("|")}`
|
|
1423
|
+
);
|
|
1424
|
+
return -1;
|
|
1425
|
+
}
|
|
1426
|
+
if(!priv.is_root) {
|
|
1427
|
+
log_error(
|
|
1428
|
+
`${GCLASS_NAME} '${node_path_str(gobj)}': nav_mode belongs to the ` +
|
|
1429
|
+
`tree ROOT — set it there, the whole tree reads it`
|
|
1430
|
+
);
|
|
1431
|
+
return -1;
|
|
1432
|
+
}
|
|
1433
|
+
gobj_write_attr(gobj, "nav_mode", mode);
|
|
1434
|
+
|
|
1435
|
+
/* Same reason as EV_SET_CHROME_DEPTH: what changes is the shape
|
|
1436
|
+
* of the ACTIVE PATH, whose strips are painted by the ancestors,
|
|
1437
|
+
* so the tree is asked to re-apply the current route instead of
|
|
1438
|
+
* repainting one node. */
|
|
1439
|
+
let shell = yui_shell_of(gobj);
|
|
1440
|
+
if(shell) {
|
|
1441
|
+
yui_shell_navigate(shell, gobj_read_attr(shell, "current_route") ||
|
|
1442
|
+
route_of(gobj), {replace: true});
|
|
1443
|
+
}
|
|
1444
|
+
return 0;
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1331
1447
|
/************************************************************
|
|
1332
1448
|
* Runtime API: change (or set) my content.
|
|
1333
1449
|
************************************************************/
|
|
@@ -1402,6 +1518,20 @@ function yui_node_set_chrome_depth(node, depth)
|
|
|
1402
1518
|
{chrome_depth: depth}, node);
|
|
1403
1519
|
}
|
|
1404
1520
|
|
|
1521
|
+
/************************************************************
|
|
1522
|
+
* The tree's navigation mode: "stack" | "back" | "path".
|
|
1523
|
+
* Send it to the ROOT — the whole tree reads it from there.
|
|
1524
|
+
************************************************************/
|
|
1525
|
+
function yui_node_set_nav_mode(node, mode)
|
|
1526
|
+
{
|
|
1527
|
+
return gobj_send_event(node, "EV_SET_NAV_MODE", {nav_mode: mode}, node);
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
function yui_node_nav_mode(node)
|
|
1531
|
+
{
|
|
1532
|
+
return gobj_read_attr(tree_root_of(node), "nav_mode") || "stack";
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1405
1535
|
/************************************************************
|
|
1406
1536
|
* Resolve a path of ids from a node ("" = the node itself).
|
|
1407
1537
|
* Returns null when any segment is missing — callers that mean
|
|
@@ -1484,6 +1614,7 @@ function create_gclass(gclass_name)
|
|
|
1484
1614
|
["EV_REMOVE_NODE", ac_remove_node, null],
|
|
1485
1615
|
["EV_SET_PROJECTION", ac_set_projection, null],
|
|
1486
1616
|
["EV_SET_CHROME_DEPTH", ac_set_chrome_depth, null],
|
|
1617
|
+
["EV_SET_NAV_MODE", ac_set_nav_mode, null],
|
|
1487
1618
|
["EV_SET_CONTENT", ac_set_content, null],
|
|
1488
1619
|
["EV_NODE_TREE_CHANGED", ac_tree_changed, null]
|
|
1489
1620
|
]],
|
|
@@ -1496,6 +1627,7 @@ function create_gclass(gclass_name)
|
|
|
1496
1627
|
["EV_REMOVE_NODE", ac_remove_node, null],
|
|
1497
1628
|
["EV_SET_PROJECTION", ac_set_projection, null],
|
|
1498
1629
|
["EV_SET_CHROME_DEPTH", ac_set_chrome_depth, null],
|
|
1630
|
+
["EV_SET_NAV_MODE", ac_set_nav_mode, null],
|
|
1499
1631
|
["EV_SET_CONTENT", ac_set_content, null],
|
|
1500
1632
|
["EV_NODE_TREE_CHANGED", ac_tree_changed, null]
|
|
1501
1633
|
]],
|
|
@@ -1508,6 +1640,7 @@ function create_gclass(gclass_name)
|
|
|
1508
1640
|
["EV_REMOVE_NODE", ac_remove_node, null],
|
|
1509
1641
|
["EV_SET_PROJECTION", ac_set_projection, null],
|
|
1510
1642
|
["EV_SET_CHROME_DEPTH", ac_set_chrome_depth, null],
|
|
1643
|
+
["EV_SET_NAV_MODE", ac_set_nav_mode, null],
|
|
1511
1644
|
["EV_SET_CONTENT", ac_set_content, null],
|
|
1512
1645
|
["EV_NODE_TREE_CHANGED", ac_tree_changed, null]
|
|
1513
1646
|
]]
|
|
@@ -1525,6 +1658,7 @@ function create_gclass(gclass_name)
|
|
|
1525
1658
|
["EV_REMOVE_NODE", 0],
|
|
1526
1659
|
["EV_SET_PROJECTION", 0],
|
|
1527
1660
|
["EV_SET_CHROME_DEPTH", 0],
|
|
1661
|
+
["EV_SET_NAV_MODE", 0],
|
|
1528
1662
|
["EV_SET_CONTENT", 0],
|
|
1529
1663
|
["EV_NODE_TREE_CHANGED", 0]
|
|
1530
1664
|
];
|
|
@@ -1565,6 +1699,8 @@ export {
|
|
|
1565
1699
|
yui_node_set_projection,
|
|
1566
1700
|
yui_node_set_content,
|
|
1567
1701
|
yui_node_set_chrome_depth,
|
|
1702
|
+
yui_node_set_nav_mode,
|
|
1703
|
+
yui_node_nav_mode,
|
|
1568
1704
|
yui_node_find,
|
|
1569
1705
|
yui_node_route,
|
|
1570
1706
|
yui_node_tree_version
|