data-navigator 2.2.4 → 2.3.1
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/dist/chunk-FP25I6TN.js +1 -0
- package/dist/chunk-RGY6OTGO.js +1 -0
- package/dist/consts.cjs +1 -1
- package/dist/consts.js +1 -1
- package/dist/index.cjs +1832 -1364
- package/dist/index.js +611 -48
- package/dist/input.cjs +1 -1
- package/dist/input.js +1 -1
- package/dist/rendering.cjs +1 -1
- package/dist/rendering.js +1 -1
- package/dist/structure.cjs +1 -1
- package/dist/structure.js +1 -1
- package/dist/text-chat.cjs +21 -0
- package/dist/text-chat.js +21 -0
- package/dist/utilities.cjs +1 -1
- package/dist/utilities.js +1 -1
- package/package.json +5 -3
- package/text-chat.css +98 -0
package/dist/index.js
CHANGED
|
@@ -1,3 +1,43 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
var __async = (__this, __arguments, generator) => {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
var fulfilled = (value) => {
|
|
23
|
+
try {
|
|
24
|
+
step(generator.next(value));
|
|
25
|
+
} catch (e) {
|
|
26
|
+
reject(e);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
var rejected = (value) => {
|
|
30
|
+
try {
|
|
31
|
+
step(generator.throw(value));
|
|
32
|
+
} catch (e) {
|
|
33
|
+
reject(e);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
37
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
|
|
1
41
|
// src/consts.ts
|
|
2
42
|
var SemanticKeys = {
|
|
3
43
|
Escape: true,
|
|
@@ -399,10 +439,11 @@ var buildNodes = (options) => {
|
|
|
399
439
|
return nodes;
|
|
400
440
|
};
|
|
401
441
|
var scaffoldDimensions = (options, nodes) => {
|
|
442
|
+
var _a, _b;
|
|
402
443
|
let dimensions = {};
|
|
403
|
-
if (options.dimensions
|
|
444
|
+
if ((_b = (_a = options.dimensions) == null ? void 0 : _a.parentOptions) == null ? void 0 : _b.addLevel0) {
|
|
404
445
|
let level0 = options.dimensions.parentOptions.addLevel0;
|
|
405
|
-
nodes[level0.id] = {
|
|
446
|
+
nodes[level0.id] = __spreadProps(__spreadValues({}, level0), { dimensionLevel: 0 });
|
|
406
447
|
}
|
|
407
448
|
let rules = [...GenericFullNavigationDimensions];
|
|
408
449
|
const setExtents = (val, dim) => {
|
|
@@ -415,6 +456,7 @@ var scaffoldDimensions = (options, nodes) => {
|
|
|
415
456
|
let ods = options.dimensions.values || [];
|
|
416
457
|
let i = 0;
|
|
417
458
|
ods.forEach((dim) => {
|
|
459
|
+
var _a2, _b2, _c, _d, _e, _f, _g, _h;
|
|
418
460
|
if (!dim.dimensionKey) {
|
|
419
461
|
console.error(
|
|
420
462
|
`Building nodes, parsing dimensions. Each dimension in options.dimensions must contain a dimensionKey. This dimension has no key: ${JSON.stringify(
|
|
@@ -425,7 +467,7 @@ var scaffoldDimensions = (options, nodes) => {
|
|
|
425
467
|
}
|
|
426
468
|
if (dim.dimensionKey in d) {
|
|
427
469
|
let value = d[dim.dimensionKey];
|
|
428
|
-
let keepValue = typeof dim.operations
|
|
470
|
+
let keepValue = typeof ((_a2 = dim.operations) == null ? void 0 : _a2.filterFunction) === "function" ? dim.operations.filterFunction(d, dim) : true;
|
|
429
471
|
if (value !== void 0 && keepValue) {
|
|
430
472
|
if (!dim.type) {
|
|
431
473
|
dim.type = typeof value === "bigint" || typeof value === "number" ? "numerical" : "categorical";
|
|
@@ -440,8 +482,8 @@ var scaffoldDimensions = (options, nodes) => {
|
|
|
440
482
|
numericalExtents: [Infinity, -Infinity],
|
|
441
483
|
type: dim.type,
|
|
442
484
|
operations: {
|
|
443
|
-
compressSparseDivisions: dim.operations
|
|
444
|
-
sortFunction: dim.operations
|
|
485
|
+
compressSparseDivisions: ((_b2 = dim.operations) == null ? void 0 : _b2.compressSparseDivisions) || false,
|
|
486
|
+
sortFunction: ((_c = dim.operations) == null ? void 0 : _c.sortFunction) || void 0
|
|
445
487
|
},
|
|
446
488
|
behavior: dim.behavior || {
|
|
447
489
|
extents: "circular"
|
|
@@ -465,23 +507,23 @@ var scaffoldDimensions = (options, nodes) => {
|
|
|
465
507
|
let dimension = dimensions[dim.dimensionKey];
|
|
466
508
|
let targetDivision = null;
|
|
467
509
|
if (dim.type === "categorical") {
|
|
468
|
-
let divisionId = typeof dim.divisionOptions
|
|
510
|
+
let divisionId = typeof ((_d = dim.divisionOptions) == null ? void 0 : _d.divisionNodeIds) === "function" ? dim.divisionOptions.divisionNodeIds(dim.dimensionKey, value, i) : createValidId(dimension.nodeId + "_" + value);
|
|
469
511
|
targetDivision = dimension.divisions[divisionId];
|
|
470
512
|
if (!targetDivision) {
|
|
471
513
|
targetDivision = dimension.divisions[divisionId] = {
|
|
472
514
|
id: divisionId,
|
|
473
|
-
sortFunction: dim.divisionOptions
|
|
515
|
+
sortFunction: ((_e = dim.divisionOptions) == null ? void 0 : _e.sortFunction) || void 0,
|
|
474
516
|
values: {}
|
|
475
517
|
};
|
|
476
|
-
let divisionRenderId = typeof dim.divisionOptions
|
|
518
|
+
let divisionRenderId = typeof ((_f = dim.divisionOptions) == null ? void 0 : _f.divisionRenderIds) === "function" ? dim.divisionOptions.divisionRenderIds(dim.dimensionKey, value, i) : divisionId;
|
|
477
519
|
nodes[divisionId] = {
|
|
478
520
|
id: divisionId,
|
|
479
521
|
renderId: divisionRenderId,
|
|
480
522
|
derivedNode: dim.dimensionKey,
|
|
481
523
|
edges: [],
|
|
482
524
|
dimensionLevel: 2,
|
|
483
|
-
data: {
|
|
484
|
-
renderingStrategy: dim.divisionOptions
|
|
525
|
+
data: __spreadValues({}, targetDivision),
|
|
526
|
+
renderingStrategy: ((_g = dim.divisionOptions) == null ? void 0 : _g.renderingStrategy) || "singleSquare"
|
|
485
527
|
// not sure what defaults we want yet
|
|
486
528
|
};
|
|
487
529
|
nodes[divisionId].data[dim.dimensionKey] = value;
|
|
@@ -491,7 +533,7 @@ var scaffoldDimensions = (options, nodes) => {
|
|
|
491
533
|
if (!targetDivision) {
|
|
492
534
|
targetDivision = dimension.divisions[dimension.nodeId] = {
|
|
493
535
|
id: dimension.nodeId,
|
|
494
|
-
sortFunction: dim.divisionOptions
|
|
536
|
+
sortFunction: ((_h = dim.divisionOptions) == null ? void 0 : _h.sortFunction) || void 0,
|
|
495
537
|
values: {}
|
|
496
538
|
};
|
|
497
539
|
}
|
|
@@ -515,12 +557,14 @@ var scaffoldDimensions = (options, nodes) => {
|
|
|
515
557
|
});
|
|
516
558
|
});
|
|
517
559
|
Object.keys(dimensions).forEach((s) => {
|
|
560
|
+
var _a2, _b2, _c, _d, _e;
|
|
518
561
|
let dimension = dimensions[s];
|
|
519
562
|
let divisions = dimension.divisions;
|
|
520
563
|
if (dimension.type === "numerical") {
|
|
521
564
|
divisions[dimension.nodeId].values = Object.fromEntries(
|
|
522
565
|
Object.entries(divisions[dimension.nodeId].values).sort((a, b) => {
|
|
523
|
-
|
|
566
|
+
var _a3;
|
|
567
|
+
return typeof ((_a3 = dimension.operations) == null ? void 0 : _a3.sortFunction) === "function" ? dimension.operations.sortFunction(a[1], b[1], dimension) : a[1][s] - b[1][s];
|
|
524
568
|
})
|
|
525
569
|
);
|
|
526
570
|
let values = divisions[dimension.nodeId].values;
|
|
@@ -533,13 +577,13 @@ var scaffoldDimensions = (options, nodes) => {
|
|
|
533
577
|
let divisionCount = 0;
|
|
534
578
|
let index = 0;
|
|
535
579
|
for (i = dimension.numericalExtents[0] + interval; i <= dimension.numericalExtents[1]; i += interval) {
|
|
536
|
-
let divisionId = typeof dimension.divisionOptions
|
|
580
|
+
let divisionId = typeof ((_a2 = dimension.divisionOptions) == null ? void 0 : _a2.divisionNodeIds) === "function" ? dimension.divisionOptions.divisionNodeIds(s, i, i) : dimension.nodeId + "_" + i;
|
|
537
581
|
dimension.divisions[divisionId] = {
|
|
538
582
|
id: divisionId,
|
|
539
|
-
sortFunction: dimension.divisionOptions
|
|
583
|
+
sortFunction: ((_b2 = dimension.divisionOptions) == null ? void 0 : _b2.sortFunction) || void 0,
|
|
540
584
|
values: {}
|
|
541
585
|
};
|
|
542
|
-
let divisionRenderId = typeof dimension.divisionOptions
|
|
586
|
+
let divisionRenderId = typeof ((_c = dimension.divisionOptions) == null ? void 0 : _c.divisionRenderIds) === "function" ? dimension.divisionOptions.divisionRenderIds(s, i, i) : divisionId;
|
|
543
587
|
nodes[divisionId] = {
|
|
544
588
|
id: divisionId,
|
|
545
589
|
renderId: divisionRenderId,
|
|
@@ -547,7 +591,7 @@ var scaffoldDimensions = (options, nodes) => {
|
|
|
547
591
|
edges: [],
|
|
548
592
|
data: dimension.divisions[divisionId],
|
|
549
593
|
dimensionLevel: 2,
|
|
550
|
-
renderingStrategy: dimension.divisionOptions
|
|
594
|
+
renderingStrategy: ((_d = dimension.divisionOptions) == null ? void 0 : _d.renderingStrategy) || "singleSquare"
|
|
551
595
|
// not sure what defaults we want yet
|
|
552
596
|
};
|
|
553
597
|
let limit = false;
|
|
@@ -566,7 +610,7 @@ var scaffoldDimensions = (options, nodes) => {
|
|
|
566
610
|
}
|
|
567
611
|
delete divisions[s];
|
|
568
612
|
}
|
|
569
|
-
} else if (typeof dimension.operations
|
|
613
|
+
} else if (typeof ((_e = dimension.operations) == null ? void 0 : _e.sortFunction) === "function") {
|
|
570
614
|
dimension.divisions = Object.fromEntries(
|
|
571
615
|
Object.entries(divisions).sort((a, b) => {
|
|
572
616
|
return dimension.operations.sortFunction(a[1], b[1], dimension);
|
|
@@ -596,7 +640,7 @@ var scaffoldDimensions = (options, nodes) => {
|
|
|
596
640
|
const valueKeys = Object.keys(division.values);
|
|
597
641
|
if (valueKeys.length <= 1) {
|
|
598
642
|
valueKeys.forEach((vk) => {
|
|
599
|
-
values[vk] = {
|
|
643
|
+
values[vk] = __spreadValues({}, division.values[vk]);
|
|
600
644
|
});
|
|
601
645
|
} else {
|
|
602
646
|
sparse = false;
|
|
@@ -621,6 +665,7 @@ var scaffoldDimensions = (options, nodes) => {
|
|
|
621
665
|
return dimensions;
|
|
622
666
|
};
|
|
623
667
|
var buildEdges = (options, nodes, dimensions) => {
|
|
668
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
624
669
|
let edges = {};
|
|
625
670
|
const addEdgeToNode = (nodeId, edgeId) => {
|
|
626
671
|
if (nodes[nodeId].edges.indexOf(edgeId) === -1) {
|
|
@@ -656,14 +701,14 @@ var buildEdges = (options, nodes, dimensions) => {
|
|
|
656
701
|
};
|
|
657
702
|
if (dimensions && Object.keys(dimensions).length) {
|
|
658
703
|
const dimensionKeys = Object.keys(dimensions);
|
|
659
|
-
const hasOrder = options.dimensions
|
|
704
|
+
const hasOrder = (_c = (_b = (_a = options.dimensions) == null ? void 0 : _a.parentOptions) == null ? void 0 : _b.level1Options) == null ? void 0 : _c.order;
|
|
660
705
|
let order = hasOrder || dimensionKeys;
|
|
661
706
|
let l = 0;
|
|
662
|
-
let po = options.dimensions
|
|
663
|
-
let extents = po.level1Options
|
|
707
|
+
let po = ((_d = options.dimensions) == null ? void 0 : _d.parentOptions) || {};
|
|
708
|
+
let extents = ((_f = (_e = po.level1Options) == null ? void 0 : _e.behavior) == null ? void 0 : _f.extents) || "terminal";
|
|
664
709
|
let level0 = po.addLevel0;
|
|
665
|
-
let parentRules = level0 ? po.level1Options
|
|
666
|
-
let siblingRules = po.level1Options
|
|
710
|
+
let parentRules = level0 ? ((_h = (_g = po.level1Options) == null ? void 0 : _g.navigationRules) == null ? void 0 : _h.parent_child) || ["parent", "child"] : [];
|
|
711
|
+
let siblingRules = ((_j = (_i = po.level1Options) == null ? void 0 : _i.navigationRules) == null ? void 0 : _j.sibling_sibling) || ["left", "right"];
|
|
667
712
|
let firstLevel1Node = typeof order[0] === "string" ? hasOrder ? nodes[order[0]] : nodes[dimensions[order[0]].nodeId] : order[0];
|
|
668
713
|
if (level0) {
|
|
669
714
|
createEdge(level0.id, firstLevel1Node.id, parentRules, "source");
|
|
@@ -700,13 +745,14 @@ var buildEdges = (options, nodes, dimensions) => {
|
|
|
700
745
|
l++;
|
|
701
746
|
});
|
|
702
747
|
dimensionKeys.forEach((s) => {
|
|
748
|
+
var _a2, _b2, _c2, _d2;
|
|
703
749
|
const dimension = dimensions[s];
|
|
704
|
-
const strat = dimension.behavior
|
|
705
|
-
const matchByIndex = (i,
|
|
750
|
+
const strat = ((_a2 = dimension.behavior) == null ? void 0 : _a2.childmostNavigation) || "within";
|
|
751
|
+
const matchByIndex = (i, _a3, _b3, c) => {
|
|
706
752
|
return c.values[Object.keys(c.values)[i]] || void 0;
|
|
707
753
|
};
|
|
708
|
-
const match = strat === "across" && dimension.behavior
|
|
709
|
-
let extents2 = dimension.behavior
|
|
754
|
+
const match = strat === "across" && ((_b2 = dimension.behavior) == null ? void 0 : _b2.childmostMatching) ? (_c2 = dimension.behavior) == null ? void 0 : _c2.childmostMatching : matchByIndex;
|
|
755
|
+
let extents2 = ((_d2 = dimension.behavior) == null ? void 0 : _d2.extents) || "circular";
|
|
710
756
|
if (!dimension.divisions) {
|
|
711
757
|
console.error(
|
|
712
758
|
`Parsing dimensions. The dimension using the key ${s} is missing the divisions property. dimension.divisions should be supplied. ${JSON.stringify(
|
|
@@ -867,8 +913,9 @@ var buildEdges = (options, nodes, dimensions) => {
|
|
|
867
913
|
});
|
|
868
914
|
}
|
|
869
915
|
Object.keys(nodes).forEach((nodeKey) => {
|
|
916
|
+
var _a2;
|
|
870
917
|
const node = nodes[nodeKey];
|
|
871
|
-
if (options.genericEdges
|
|
918
|
+
if ((_a2 = options.genericEdges) == null ? void 0 : _a2.length) {
|
|
872
919
|
options.genericEdges.forEach((e) => {
|
|
873
920
|
if (!edges[e.edgeId]) {
|
|
874
921
|
edges[e.edgeId] = e.edge;
|
|
@@ -882,6 +929,7 @@ var buildEdges = (options, nodes, dimensions) => {
|
|
|
882
929
|
return edges;
|
|
883
930
|
};
|
|
884
931
|
var buildRules = (options, edges, dimensions) => {
|
|
932
|
+
var _a, _b, _c, _d;
|
|
885
933
|
let rules = options.navigationRules;
|
|
886
934
|
if (!rules) {
|
|
887
935
|
let dimKeys = Object.keys(dimensions || {});
|
|
@@ -900,11 +948,11 @@ var buildRules = (options, edges, dimensions) => {
|
|
|
900
948
|
let k1Assigned = false;
|
|
901
949
|
let k2Assigned = false;
|
|
902
950
|
if (importedRules[k1] || used[k1]) {
|
|
903
|
-
used[k1] = {
|
|
951
|
+
used[k1] = __spreadValues({}, importedRules[k1]);
|
|
904
952
|
k1Assigned = true;
|
|
905
953
|
}
|
|
906
954
|
if (k2 && (importedRules[k2] || used[k2])) {
|
|
907
|
-
used[k2] = {
|
|
955
|
+
used[k2] = __spreadValues({}, importedRules[k2]);
|
|
908
956
|
k2Assigned = true;
|
|
909
957
|
}
|
|
910
958
|
if (isPair && !k1Assigned && !k2Assigned) {
|
|
@@ -964,15 +1012,15 @@ var buildRules = (options, edges, dimensions) => {
|
|
|
964
1012
|
}
|
|
965
1013
|
};
|
|
966
1014
|
Object.keys(GenericFullNavigationRules).forEach((r) => {
|
|
967
|
-
let rule = {
|
|
1015
|
+
let rule = __spreadValues({}, GenericFullNavigationRules[r]);
|
|
968
1016
|
if (options.useDirectedEdges) {
|
|
969
1017
|
rule.direction = "target";
|
|
970
1018
|
}
|
|
971
1019
|
importedRules[r] = rule;
|
|
972
1020
|
});
|
|
973
1021
|
if (dimKeys.length) {
|
|
974
|
-
if (options.dimensions
|
|
975
|
-
let rules2 = options.dimensions.parentOptions.level1Options
|
|
1022
|
+
if ((_b = (_a = options.dimensions) == null ? void 0 : _a.parentOptions) == null ? void 0 : _b.addLevel0) {
|
|
1023
|
+
let rules2 = ((_d = (_c = options.dimensions.parentOptions.level1Options) == null ? void 0 : _c.navigationRules) == null ? void 0 : _d.parent_child) || [
|
|
976
1024
|
"parent",
|
|
977
1025
|
"child"
|
|
978
1026
|
];
|
|
@@ -1002,7 +1050,7 @@ var buildRules = (options, edges, dimensions) => {
|
|
|
1002
1050
|
spareKeys.push(importedRules[r].key);
|
|
1003
1051
|
}
|
|
1004
1052
|
});
|
|
1005
|
-
let recheckKeys = {
|
|
1053
|
+
let recheckKeys = __spreadValues({}, needsKeys);
|
|
1006
1054
|
needsKeys = {};
|
|
1007
1055
|
Object.keys(recheckKeys).forEach((key) => {
|
|
1008
1056
|
checkKeys(key);
|
|
@@ -1142,19 +1190,20 @@ var rendering_default = (options) => {
|
|
|
1142
1190
|
let initialized = false;
|
|
1143
1191
|
let defaults = {
|
|
1144
1192
|
cssClass: NodeElementDefaults.cssClass,
|
|
1145
|
-
spatialProperties: {
|
|
1146
|
-
semantics: {
|
|
1147
|
-
parentSemantics: {
|
|
1148
|
-
existingElement: {
|
|
1193
|
+
spatialProperties: __spreadValues({}, NodeElementDefaults.spatialProperties),
|
|
1194
|
+
semantics: __spreadValues({}, NodeElementDefaults.semantics),
|
|
1195
|
+
parentSemantics: __spreadValues({}, NodeElementDefaults.parentSemantics),
|
|
1196
|
+
existingElement: __spreadValues({}, NodeElementDefaults.existingElement)
|
|
1149
1197
|
};
|
|
1150
1198
|
if (options.defaults) {
|
|
1151
1199
|
defaults.cssClass = options.defaults.cssClass || defaults.cssClass;
|
|
1152
|
-
defaults.spatialProperties = options.defaults.spatialProperties ? {
|
|
1153
|
-
defaults.semantics = options.defaults.semantics ? {
|
|
1154
|
-
defaults.parentSemantics = options.defaults.parentSemantics ? {
|
|
1155
|
-
defaults.existingElement = options.defaults.existingElement ? {
|
|
1200
|
+
defaults.spatialProperties = options.defaults.spatialProperties ? __spreadValues(__spreadValues({}, defaults.spatialProperties), options.defaults.spatialProperties) : defaults.spatialProperties;
|
|
1201
|
+
defaults.semantics = options.defaults.semantics ? __spreadValues(__spreadValues({}, defaults.semantics), options.defaults.semantics) : defaults.semantics;
|
|
1202
|
+
defaults.parentSemantics = options.defaults.parentSemantics ? __spreadValues(__spreadValues({}, defaults.parentSemantics), options.defaults.parentSemantics) : defaults.parentSemantics;
|
|
1203
|
+
defaults.existingElement = options.defaults.existingElement ? __spreadValues(__spreadValues({}, defaults.existingElement), options.defaults.existingElement) : defaults.existingElement;
|
|
1156
1204
|
}
|
|
1157
1205
|
renderer.initialize = () => {
|
|
1206
|
+
var _a;
|
|
1158
1207
|
if (initialized) {
|
|
1159
1208
|
console.error(
|
|
1160
1209
|
`The renderer wrapper has already been initialized successfully, RenderingOptions.suffixId is: ${options.suffixId}. No further action was taken.`
|
|
@@ -1199,7 +1248,7 @@ var rendering_default = (options) => {
|
|
|
1199
1248
|
renderer.wrapper.appendChild(renderer.entryButton);
|
|
1200
1249
|
}
|
|
1201
1250
|
renderer.root.appendChild(renderer.wrapper);
|
|
1202
|
-
if (options.exitElement
|
|
1251
|
+
if ((_a = options.exitElement) == null ? void 0 : _a.include) {
|
|
1203
1252
|
renderer.exitElement = document.createElement("div");
|
|
1204
1253
|
renderer.exitElement.id = "dn-exit-" + options.suffixId;
|
|
1205
1254
|
renderer.exitElement.classList.add("dn-exit-position");
|
|
@@ -1209,15 +1258,17 @@ var rendering_default = (options) => {
|
|
|
1209
1258
|
renderer.exitElement.setAttribute("tabindex", "-1");
|
|
1210
1259
|
renderer.exitElement.style.display = "none";
|
|
1211
1260
|
renderer.exitElement.addEventListener("focus", (e) => {
|
|
1261
|
+
var _a2, _b;
|
|
1212
1262
|
renderer.exitElement.style.display = "block";
|
|
1213
1263
|
renderer.clearStructure();
|
|
1214
|
-
if (options.exitElement
|
|
1264
|
+
if ((_b = (_a2 = options.exitElement) == null ? void 0 : _a2.callbacks) == null ? void 0 : _b.focus) {
|
|
1215
1265
|
options.exitElement.callbacks.focus(e);
|
|
1216
1266
|
}
|
|
1217
1267
|
});
|
|
1218
1268
|
renderer.exitElement.addEventListener("blur", (e) => {
|
|
1269
|
+
var _a2, _b;
|
|
1219
1270
|
renderer.exitElement.style.display = "none";
|
|
1220
|
-
if (options.exitElement
|
|
1271
|
+
if ((_b = (_a2 = options.exitElement) == null ? void 0 : _a2.callbacks) == null ? void 0 : _b.blur) {
|
|
1221
1272
|
options.exitElement.callbacks.blur(e);
|
|
1222
1273
|
}
|
|
1223
1274
|
});
|
|
@@ -1240,9 +1291,10 @@ var rendering_default = (options) => {
|
|
|
1240
1291
|
let useExisting = false;
|
|
1241
1292
|
let existingSpatialProperties = {};
|
|
1242
1293
|
const resolveProp = (prop, subprop, checkExisting) => {
|
|
1294
|
+
var _a;
|
|
1243
1295
|
const p1 = d[prop] || defaults[prop];
|
|
1244
|
-
const s1 = !(checkExisting && useExisting) ? p1
|
|
1245
|
-
const s2 = defaults[prop]
|
|
1296
|
+
const s1 = !(checkExisting && useExisting) ? p1 == null ? void 0 : p1[subprop] : existingSpatialProperties[subprop];
|
|
1297
|
+
const s2 = (_a = defaults[prop]) == null ? void 0 : _a[subprop];
|
|
1246
1298
|
return typeof p1 === "function" ? p1(d, nodeData.datum) : typeof s1 === "function" ? s1(d, nodeData.datum) : s1 || s2 || (!subprop ? p1 : void 0);
|
|
1247
1299
|
};
|
|
1248
1300
|
useExisting = resolveProp("existingElement", "useForSpatialProperties");
|
|
@@ -1332,8 +1384,519 @@ var rendering_default = (options) => {
|
|
|
1332
1384
|
return renderer;
|
|
1333
1385
|
};
|
|
1334
1386
|
|
|
1387
|
+
// src/text-chat.ts
|
|
1388
|
+
var defaultDescribeNode = (node) => {
|
|
1389
|
+
var _a, _b, _c, _d, _e;
|
|
1390
|
+
if ((_a = node.semantics) == null ? void 0 : _a.label) {
|
|
1391
|
+
const label = typeof node.semantics.label === "function" ? node.semantics.label() : node.semantics.label;
|
|
1392
|
+
if (label)
|
|
1393
|
+
return label;
|
|
1394
|
+
}
|
|
1395
|
+
if (!node.derivedNode) {
|
|
1396
|
+
if (node.data) {
|
|
1397
|
+
return Object.keys(node.data).map((key) => `${key}: ${node.data[key]}`).join(". ") + ". Data point.";
|
|
1398
|
+
}
|
|
1399
|
+
return node.id;
|
|
1400
|
+
}
|
|
1401
|
+
if ((_b = node.data) == null ? void 0 : _b.dimensionKey) {
|
|
1402
|
+
let count = 0;
|
|
1403
|
+
const divisions = Object.keys(node.data.divisions || {});
|
|
1404
|
+
divisions.forEach((div) => {
|
|
1405
|
+
count += Object.keys(node.data.divisions[div].values || {}).length;
|
|
1406
|
+
});
|
|
1407
|
+
let label = `${node.derivedNode}.`;
|
|
1408
|
+
label += divisions.length && count ? ` ${divisions.length} division${divisions.length > 1 ? "s" : ""}, ${count} datapoint${count > 1 ? "s" : ""}.` : " No child data points.";
|
|
1409
|
+
label += ` ${node.data.type} dimension.`;
|
|
1410
|
+
return label;
|
|
1411
|
+
}
|
|
1412
|
+
return `${node.derivedNode}: ${(_c = node.data) == null ? void 0 : _c[node.derivedNode]}. ${Object.keys(((_d = node.data) == null ? void 0 : _d.values) || {}).length} child data point${Object.keys(((_e = node.data) == null ? void 0 : _e.values) || {}).length > 1 ? "s" : ""}. Division.`;
|
|
1413
|
+
};
|
|
1414
|
+
var getAvailableRules = (nodeId, node, structure) => {
|
|
1415
|
+
const available = /* @__PURE__ */ new Set();
|
|
1416
|
+
const navRules = structure.navigationRules || {};
|
|
1417
|
+
if (node.edges) {
|
|
1418
|
+
node.edges.forEach((edgeId) => {
|
|
1419
|
+
const edge = structure.edges[edgeId];
|
|
1420
|
+
if (!edge)
|
|
1421
|
+
return;
|
|
1422
|
+
edge.navigationRules.forEach((ruleName) => {
|
|
1423
|
+
const navRule = navRules[ruleName];
|
|
1424
|
+
if (!navRule)
|
|
1425
|
+
return;
|
|
1426
|
+
const endpoint = navRule.direction === "target" ? edge.target : edge.source;
|
|
1427
|
+
const resolved = typeof endpoint === "function" ? endpoint(node, nodeId) : endpoint;
|
|
1428
|
+
if (resolved && resolved !== nodeId) {
|
|
1429
|
+
available.add(ruleName);
|
|
1430
|
+
}
|
|
1431
|
+
});
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
return Array.from(available);
|
|
1435
|
+
};
|
|
1436
|
+
var getAllRuleNames = (structure) => {
|
|
1437
|
+
if (!structure.navigationRules)
|
|
1438
|
+
return [];
|
|
1439
|
+
return Object.keys(structure.navigationRules);
|
|
1440
|
+
};
|
|
1441
|
+
var damerauLevenshtein = (a, b) => {
|
|
1442
|
+
const m = a.length;
|
|
1443
|
+
const n = b.length;
|
|
1444
|
+
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
|
|
1445
|
+
for (let i = 0; i <= m; i++)
|
|
1446
|
+
dp[i][0] = i;
|
|
1447
|
+
for (let j = 0; j <= n; j++)
|
|
1448
|
+
dp[0][j] = j;
|
|
1449
|
+
for (let i = 1; i <= m; i++) {
|
|
1450
|
+
for (let j = 1; j <= n; j++) {
|
|
1451
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
1452
|
+
dp[i][j] = Math.min(
|
|
1453
|
+
dp[i - 1][j] + 1,
|
|
1454
|
+
// deletion
|
|
1455
|
+
dp[i][j - 1] + 1,
|
|
1456
|
+
// insertion
|
|
1457
|
+
dp[i - 1][j - 1] + cost
|
|
1458
|
+
// substitution
|
|
1459
|
+
);
|
|
1460
|
+
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
|
|
1461
|
+
dp[i][j] = Math.min(dp[i][j], dp[i - 2][j - 2] + cost);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
return dp[m][n];
|
|
1466
|
+
};
|
|
1467
|
+
var maxTypoDistance = (len) => len <= 4 ? 1 : 2;
|
|
1468
|
+
var fuzzyMatch = (input, candidates, labels = {}) => {
|
|
1469
|
+
const lower = input.toLowerCase().trim();
|
|
1470
|
+
const exactName = candidates.find((c) => c.toLowerCase() === lower);
|
|
1471
|
+
if (exactName)
|
|
1472
|
+
return { match: exactName, ambiguous: [] };
|
|
1473
|
+
const exactLabel = candidates.find(
|
|
1474
|
+
(c) => labels[c] && labels[c].toLowerCase() === lower
|
|
1475
|
+
);
|
|
1476
|
+
if (exactLabel)
|
|
1477
|
+
return { match: exactLabel, ambiguous: [] };
|
|
1478
|
+
const namePrefix = candidates.filter((c) => c.toLowerCase().startsWith(lower));
|
|
1479
|
+
if (namePrefix.length === 1)
|
|
1480
|
+
return { match: namePrefix[0], ambiguous: [] };
|
|
1481
|
+
const labelMatches = candidates.filter((c) => {
|
|
1482
|
+
if (!labels[c])
|
|
1483
|
+
return false;
|
|
1484
|
+
const labelLower = labels[c].toLowerCase();
|
|
1485
|
+
if (labelLower.startsWith(lower))
|
|
1486
|
+
return true;
|
|
1487
|
+
return labelLower.split(/\s+/).some((word) => word.startsWith(lower));
|
|
1488
|
+
});
|
|
1489
|
+
const combined = /* @__PURE__ */ new Set([...namePrefix, ...labelMatches]);
|
|
1490
|
+
const all = Array.from(combined);
|
|
1491
|
+
if (all.length === 1)
|
|
1492
|
+
return { match: all[0], ambiguous: [] };
|
|
1493
|
+
if (all.length > 1)
|
|
1494
|
+
return { match: null, ambiguous: all };
|
|
1495
|
+
const threshold = maxTypoDistance(lower.length);
|
|
1496
|
+
const typoMatches = [];
|
|
1497
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
1498
|
+
const c = candidates[i];
|
|
1499
|
+
const nameDist = damerauLevenshtein(lower, c.toLowerCase());
|
|
1500
|
+
if (nameDist <= threshold) {
|
|
1501
|
+
typoMatches.push({ candidate: c, dist: nameDist });
|
|
1502
|
+
continue;
|
|
1503
|
+
}
|
|
1504
|
+
if (labels[c]) {
|
|
1505
|
+
const words = labels[c].toLowerCase().split(/\s+/);
|
|
1506
|
+
for (let w = 0; w < words.length; w++) {
|
|
1507
|
+
if (damerauLevenshtein(lower, words[w]) <= threshold) {
|
|
1508
|
+
typoMatches.push({ candidate: c, dist: damerauLevenshtein(lower, words[w]) });
|
|
1509
|
+
break;
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
if (typoMatches.length === 1)
|
|
1515
|
+
return { match: typoMatches[0].candidate, ambiguous: [] };
|
|
1516
|
+
if (typoMatches.length > 1) {
|
|
1517
|
+
typoMatches.sort((a, b) => a.dist - b.dist);
|
|
1518
|
+
if (typoMatches[0].dist < typoMatches[1].dist) {
|
|
1519
|
+
return { match: typoMatches[0].candidate, ambiguous: [] };
|
|
1520
|
+
}
|
|
1521
|
+
return { match: null, ambiguous: typoMatches.map((t) => t.candidate) };
|
|
1522
|
+
}
|
|
1523
|
+
return { match: null, ambiguous: [] };
|
|
1524
|
+
};
|
|
1525
|
+
var formatRule = (ruleName, labels) => {
|
|
1526
|
+
if (labels[ruleName])
|
|
1527
|
+
return `${labels[ruleName]} (${ruleName})`;
|
|
1528
|
+
return ruleName;
|
|
1529
|
+
};
|
|
1530
|
+
var searchNodes = (query, structure, describeFn, limit = 10) => {
|
|
1531
|
+
const lower = query.toLowerCase();
|
|
1532
|
+
const results = [];
|
|
1533
|
+
const nodeIds = Object.keys(structure.nodes);
|
|
1534
|
+
for (let i = 0; i < nodeIds.length && results.length < limit; i++) {
|
|
1535
|
+
const nodeId = nodeIds[i];
|
|
1536
|
+
const node = structure.nodes[nodeId];
|
|
1537
|
+
let matched = false;
|
|
1538
|
+
if (node.data && !matched) {
|
|
1539
|
+
const dataKeys = Object.keys(node.data);
|
|
1540
|
+
for (let j = 0; j < dataKeys.length && !matched; j++) {
|
|
1541
|
+
const val = node.data[dataKeys[j]];
|
|
1542
|
+
if (val != null && typeof val !== "object" && String(val).toLowerCase().includes(lower)) {
|
|
1543
|
+
matched = true;
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
if (!matched && node.derivedNode && node.derivedNode.toLowerCase().includes(lower)) {
|
|
1548
|
+
matched = true;
|
|
1549
|
+
}
|
|
1550
|
+
if (!matched && nodeId.toLowerCase().includes(lower)) {
|
|
1551
|
+
matched = true;
|
|
1552
|
+
}
|
|
1553
|
+
if (matched) {
|
|
1554
|
+
results.push({ nodeId, description: describeFn(node) });
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
return results;
|
|
1558
|
+
};
|
|
1559
|
+
var text_chat_default = (options) => {
|
|
1560
|
+
var _a;
|
|
1561
|
+
const {
|
|
1562
|
+
structure,
|
|
1563
|
+
container,
|
|
1564
|
+
entryPoint,
|
|
1565
|
+
describeNode: describeNode2 = defaultDescribeNode,
|
|
1566
|
+
commandLabels = {},
|
|
1567
|
+
onNavigate,
|
|
1568
|
+
onExit,
|
|
1569
|
+
llm,
|
|
1570
|
+
data
|
|
1571
|
+
} = options;
|
|
1572
|
+
const rootEl = typeof container === "string" ? document.getElementById(container) : container;
|
|
1573
|
+
if (!rootEl) {
|
|
1574
|
+
throw new Error(`textChat: container "${container}" not found`);
|
|
1575
|
+
}
|
|
1576
|
+
const resolvedEntryPoint = entryPoint || (structure.dimensions ? (_a = structure.dimensions[Object.keys(structure.dimensions)[0]]) == null ? void 0 : _a.nodeId : Object.keys(structure.nodes)[0]);
|
|
1577
|
+
const inputHandler = input_default({
|
|
1578
|
+
structure,
|
|
1579
|
+
navigationRules: structure.navigationRules || {},
|
|
1580
|
+
entryPoint: resolvedEntryPoint
|
|
1581
|
+
});
|
|
1582
|
+
let currentNodeId = null;
|
|
1583
|
+
const uid = Math.random().toString(36).slice(2, 8);
|
|
1584
|
+
const history = [];
|
|
1585
|
+
let historyIndex = -1;
|
|
1586
|
+
let pendingChoices = null;
|
|
1587
|
+
const llmHistory = [];
|
|
1588
|
+
const buildSystemPrompt = () => {
|
|
1589
|
+
let prompt = "You are a data assistant helping a user explore a dataset through a text-based navigation interface.\n\n";
|
|
1590
|
+
if (data && data.length > 0) {
|
|
1591
|
+
const columns = Object.keys(data[0]);
|
|
1592
|
+
const sampleRows = data.slice(0, 3).map((r) => JSON.stringify(r)).join("\n ");
|
|
1593
|
+
prompt += `DATASET SUMMARY:
|
|
1594
|
+
- Columns: ${columns.join(", ")}
|
|
1595
|
+
- Rows: ${data.length}
|
|
1596
|
+
- Sample (first 3):
|
|
1597
|
+
${sampleRows}
|
|
1598
|
+
|
|
1599
|
+
`;
|
|
1600
|
+
prompt += "FULL DATASET (JSON):\n" + JSON.stringify(data) + "\n\n";
|
|
1601
|
+
}
|
|
1602
|
+
if (currentNodeId) {
|
|
1603
|
+
const node = structure.nodes[currentNodeId];
|
|
1604
|
+
prompt += `CURRENT POSITION: ${node ? describeNode2(node) : currentNodeId}
|
|
1605
|
+
|
|
1606
|
+
`;
|
|
1607
|
+
} else {
|
|
1608
|
+
prompt += "CURRENT POSITION: Not yet navigated into the structure.\n\n";
|
|
1609
|
+
}
|
|
1610
|
+
prompt += "PRIORITY: Always prefer answers that can be verified against the dataset. For any statistical or quantitative claim (averages, comparisons, trends, extremes), briefly describe the method you used. Avoid open-ended or contextual claims that go beyond what the data can support \u2014 if the user asks something that cannot be checked against the dataset, say so and suggest they verify externally.\n\n";
|
|
1611
|
+
prompt += "VERIFICATION: When the user asks you to verify a claim, write a short Python script (using the dataset as a JSON array) that computes the answer, and show the expected output. If the claim is too open-ended to verify with code, explain why and recommend external verification.\n\n";
|
|
1612
|
+
prompt += 'IMPORTANT: Your responses may contain errors. The user has been told they can ask you to "verify" any answer, and you will attempt to provide a Python script to check it.';
|
|
1613
|
+
return prompt;
|
|
1614
|
+
};
|
|
1615
|
+
const chatEl = document.createElement("div");
|
|
1616
|
+
chatEl.className = "dn-text-chat";
|
|
1617
|
+
const logEl = document.createElement("div");
|
|
1618
|
+
logEl.className = "dn-text-chat-log";
|
|
1619
|
+
logEl.setAttribute("role", "log");
|
|
1620
|
+
logEl.setAttribute("aria-live", "polite");
|
|
1621
|
+
chatEl.appendChild(logEl);
|
|
1622
|
+
const controlsEl = document.createElement("div");
|
|
1623
|
+
controlsEl.className = "dn-text-chat-controls";
|
|
1624
|
+
const announceLabel = document.createElement("label");
|
|
1625
|
+
const announceCheckbox = document.createElement("input");
|
|
1626
|
+
announceCheckbox.type = "checkbox";
|
|
1627
|
+
announceCheckbox.checked = true;
|
|
1628
|
+
announceCheckbox.addEventListener("change", () => {
|
|
1629
|
+
logEl.setAttribute("aria-live", announceCheckbox.checked ? "polite" : "off");
|
|
1630
|
+
});
|
|
1631
|
+
announceLabel.appendChild(announceCheckbox);
|
|
1632
|
+
announceLabel.appendChild(document.createTextNode(" Automatically announce to screen readers"));
|
|
1633
|
+
controlsEl.appendChild(announceLabel);
|
|
1634
|
+
chatEl.appendChild(controlsEl);
|
|
1635
|
+
const formEl = document.createElement("form");
|
|
1636
|
+
formEl.className = "dn-text-chat-form";
|
|
1637
|
+
const inputLabel = document.createElement("label");
|
|
1638
|
+
inputLabel.setAttribute("for", `dn-text-chat-input-${uid}`);
|
|
1639
|
+
inputLabel.className = "dn-text-chat-sr-only";
|
|
1640
|
+
inputLabel.textContent = "Navigation command";
|
|
1641
|
+
const inputEl = document.createElement("input");
|
|
1642
|
+
inputEl.type = "text";
|
|
1643
|
+
inputEl.id = `dn-text-chat-input-${uid}`;
|
|
1644
|
+
inputEl.autocomplete = "off";
|
|
1645
|
+
inputEl.setAttribute("placeholder", "Type a command...");
|
|
1646
|
+
const submitBtn = document.createElement("button");
|
|
1647
|
+
submitBtn.type = "submit";
|
|
1648
|
+
submitBtn.textContent = "Send";
|
|
1649
|
+
formEl.appendChild(inputLabel);
|
|
1650
|
+
formEl.appendChild(inputEl);
|
|
1651
|
+
formEl.appendChild(submitBtn);
|
|
1652
|
+
chatEl.appendChild(formEl);
|
|
1653
|
+
rootEl.appendChild(chatEl);
|
|
1654
|
+
let savedInput = "";
|
|
1655
|
+
inputEl.addEventListener("keydown", (e) => {
|
|
1656
|
+
if (e.key === "ArrowUp") {
|
|
1657
|
+
e.preventDefault();
|
|
1658
|
+
if (history.length === 0)
|
|
1659
|
+
return;
|
|
1660
|
+
if (historyIndex === -1) {
|
|
1661
|
+
savedInput = inputEl.value;
|
|
1662
|
+
historyIndex = history.length - 1;
|
|
1663
|
+
} else if (historyIndex > 0) {
|
|
1664
|
+
historyIndex--;
|
|
1665
|
+
}
|
|
1666
|
+
inputEl.value = history[historyIndex];
|
|
1667
|
+
} else if (e.key === "ArrowDown") {
|
|
1668
|
+
e.preventDefault();
|
|
1669
|
+
if (historyIndex === -1)
|
|
1670
|
+
return;
|
|
1671
|
+
if (historyIndex < history.length - 1) {
|
|
1672
|
+
historyIndex++;
|
|
1673
|
+
inputEl.value = history[historyIndex];
|
|
1674
|
+
} else {
|
|
1675
|
+
historyIndex = -1;
|
|
1676
|
+
inputEl.value = savedInput;
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
});
|
|
1680
|
+
const addMessage = (text, className) => {
|
|
1681
|
+
const msg = document.createElement("div");
|
|
1682
|
+
msg.className = `dn-text-chat-message ${className}`;
|
|
1683
|
+
msg.textContent = text;
|
|
1684
|
+
logEl.appendChild(msg);
|
|
1685
|
+
logEl.scrollTop = logEl.scrollHeight;
|
|
1686
|
+
};
|
|
1687
|
+
const addSystemMessage = (text) => addMessage(text, "dn-text-chat-system");
|
|
1688
|
+
const addEcho = (text) => addMessage(`> ${text}`, "dn-text-chat-input-echo");
|
|
1689
|
+
const addResponse = (text) => addMessage(text, "dn-text-chat-response");
|
|
1690
|
+
const addResponseWithList = (intro, items) => {
|
|
1691
|
+
const wrapper = document.createElement("div");
|
|
1692
|
+
wrapper.className = "dn-text-chat-message dn-text-chat-response";
|
|
1693
|
+
const p = document.createElement("span");
|
|
1694
|
+
p.textContent = intro;
|
|
1695
|
+
wrapper.appendChild(p);
|
|
1696
|
+
const ol = document.createElement("ol");
|
|
1697
|
+
ol.className = "dn-text-chat-choices";
|
|
1698
|
+
items.forEach((item) => {
|
|
1699
|
+
const li = document.createElement("li");
|
|
1700
|
+
li.textContent = item;
|
|
1701
|
+
ol.appendChild(li);
|
|
1702
|
+
});
|
|
1703
|
+
wrapper.appendChild(ol);
|
|
1704
|
+
logEl.appendChild(wrapper);
|
|
1705
|
+
logEl.scrollTop = logEl.scrollHeight;
|
|
1706
|
+
};
|
|
1707
|
+
const askLLM = (question) => __async(void 0, null, function* () {
|
|
1708
|
+
const systemMsg = { role: "system", content: buildSystemPrompt() };
|
|
1709
|
+
llmHistory.push({ role: "user", content: question });
|
|
1710
|
+
const thinkingMsg = document.createElement("div");
|
|
1711
|
+
thinkingMsg.className = "dn-text-chat-message dn-text-chat-llm-thinking";
|
|
1712
|
+
thinkingMsg.textContent = "Thinking...";
|
|
1713
|
+
logEl.appendChild(thinkingMsg);
|
|
1714
|
+
logEl.scrollTop = logEl.scrollHeight;
|
|
1715
|
+
try {
|
|
1716
|
+
const response = yield llm([systemMsg, ...llmHistory]);
|
|
1717
|
+
logEl.removeChild(thinkingMsg);
|
|
1718
|
+
if (response === null) {
|
|
1719
|
+
llmHistory.pop();
|
|
1720
|
+
return null;
|
|
1721
|
+
}
|
|
1722
|
+
llmHistory.push({ role: "assistant", content: response });
|
|
1723
|
+
addResponse(response);
|
|
1724
|
+
return response;
|
|
1725
|
+
} catch (err) {
|
|
1726
|
+
logEl.removeChild(thinkingMsg);
|
|
1727
|
+
llmHistory.pop();
|
|
1728
|
+
addResponse(`Error: ${err.message || "Could not get a response."}`);
|
|
1729
|
+
return "";
|
|
1730
|
+
}
|
|
1731
|
+
});
|
|
1732
|
+
if (llm) {
|
|
1733
|
+
addSystemMessage('Text navigation ready. Type "enter" to begin navigating, "help" for commands, or ask a question about the data.');
|
|
1734
|
+
addSystemMessage('Note: AI-generated answers may be inaccurate. You can ask the model to "verify" any answer \u2014 it will attempt to provide a Python script that checks the claim against the dataset. If a claim cannot be verified with code, it should be verified externally.');
|
|
1735
|
+
} else {
|
|
1736
|
+
addSystemMessage('Text navigation ready. Type "enter" to begin or "help" for available commands.');
|
|
1737
|
+
}
|
|
1738
|
+
const specialCommands = ["enter", "help", "more", "more help", "clear"];
|
|
1739
|
+
const moveToNode = (nodeId) => {
|
|
1740
|
+
const node = inputHandler.moveTo(nodeId);
|
|
1741
|
+
if (node) {
|
|
1742
|
+
currentNodeId = node.id;
|
|
1743
|
+
if (onNavigate)
|
|
1744
|
+
onNavigate(node);
|
|
1745
|
+
addResponse(`Moved to: ${describeNode2(node)}`);
|
|
1746
|
+
} else {
|
|
1747
|
+
addResponse("Could not move to that node.");
|
|
1748
|
+
}
|
|
1749
|
+
};
|
|
1750
|
+
const handleCommand = (raw) => __async(void 0, null, function* () {
|
|
1751
|
+
const trimmed = raw.trim();
|
|
1752
|
+
if (!trimmed)
|
|
1753
|
+
return;
|
|
1754
|
+
addEcho(trimmed);
|
|
1755
|
+
const lower = trimmed.toLowerCase();
|
|
1756
|
+
if (pendingChoices) {
|
|
1757
|
+
const num = parseInt(trimmed, 10);
|
|
1758
|
+
if (!isNaN(num) && num >= 1 && num <= pendingChoices.length) {
|
|
1759
|
+
const choice = pendingChoices[num - 1];
|
|
1760
|
+
pendingChoices = null;
|
|
1761
|
+
moveToNode(choice.nodeId);
|
|
1762
|
+
return;
|
|
1763
|
+
}
|
|
1764
|
+
pendingChoices = null;
|
|
1765
|
+
}
|
|
1766
|
+
if (lower === "clear") {
|
|
1767
|
+
logEl.innerHTML = "";
|
|
1768
|
+
addSystemMessage('Chat cleared. Type "help" for available commands.');
|
|
1769
|
+
return;
|
|
1770
|
+
}
|
|
1771
|
+
if (lower === "enter") {
|
|
1772
|
+
if (currentNodeId) {
|
|
1773
|
+
addResponse('Already in the structure. Type "help" to see available commands.');
|
|
1774
|
+
return;
|
|
1775
|
+
}
|
|
1776
|
+
const entryNode = inputHandler.enter();
|
|
1777
|
+
if (!entryNode) {
|
|
1778
|
+
addResponse("Could not enter the structure. No entry point found.");
|
|
1779
|
+
return;
|
|
1780
|
+
}
|
|
1781
|
+
currentNodeId = entryNode.id;
|
|
1782
|
+
if (onNavigate)
|
|
1783
|
+
onNavigate(entryNode);
|
|
1784
|
+
addResponse(`Entered: ${describeNode2(entryNode)}`);
|
|
1785
|
+
return;
|
|
1786
|
+
}
|
|
1787
|
+
if (lower === "help") {
|
|
1788
|
+
const llmHint = llm ? " You can also type any question about the data." : "";
|
|
1789
|
+
if (!currentNodeId) {
|
|
1790
|
+
addResponse(
|
|
1791
|
+
'Not yet in the structure. Type "enter" to begin navigating, or "move to <search>" to jump to a node.' + llmHint
|
|
1792
|
+
);
|
|
1793
|
+
} else {
|
|
1794
|
+
const node = structure.nodes[currentNodeId];
|
|
1795
|
+
const available = getAvailableRules(currentNodeId, node, structure);
|
|
1796
|
+
const formatted = available.map((r) => formatRule(r, commandLabels));
|
|
1797
|
+
addResponse(`Available: ${formatted.join(", ")}, move to <search>.` + llmHint);
|
|
1798
|
+
}
|
|
1799
|
+
return;
|
|
1800
|
+
}
|
|
1801
|
+
if (lower.startsWith("move to ")) {
|
|
1802
|
+
const query = trimmed.slice("move to ".length).trim();
|
|
1803
|
+
if (!query) {
|
|
1804
|
+
addResponse("Usage: move to <search term>");
|
|
1805
|
+
return;
|
|
1806
|
+
}
|
|
1807
|
+
const results = searchNodes(query, structure, describeNode2);
|
|
1808
|
+
if (results.length === 0) {
|
|
1809
|
+
addResponse(`No nodes found matching "${query}".`);
|
|
1810
|
+
} else if (results.length === 1) {
|
|
1811
|
+
moveToNode(results[0].nodeId);
|
|
1812
|
+
} else {
|
|
1813
|
+
pendingChoices = results;
|
|
1814
|
+
addResponseWithList(
|
|
1815
|
+
`Found ${results.length} matches. Type a number to move there:`,
|
|
1816
|
+
results.map((r) => r.description)
|
|
1817
|
+
);
|
|
1818
|
+
}
|
|
1819
|
+
return;
|
|
1820
|
+
}
|
|
1821
|
+
if (lower === "more" || lower === "more help") {
|
|
1822
|
+
const allRules2 = getAllRuleNames(structure);
|
|
1823
|
+
const formatted = allRules2.map((r) => formatRule(r, commandLabels));
|
|
1824
|
+
addResponse(`All navigation rules: ${formatted.join(", ")}.`);
|
|
1825
|
+
return;
|
|
1826
|
+
}
|
|
1827
|
+
if (!currentNodeId) {
|
|
1828
|
+
if (llm) {
|
|
1829
|
+
const response = yield askLLM(trimmed);
|
|
1830
|
+
if (response !== null)
|
|
1831
|
+
return;
|
|
1832
|
+
}
|
|
1833
|
+
const llmHint = llm ? " Enter an API key above to ask questions about the data." : "";
|
|
1834
|
+
addResponse('Type "enter" to begin navigating the structure, or "move to <search>" to jump to a node.' + llmHint);
|
|
1835
|
+
return;
|
|
1836
|
+
}
|
|
1837
|
+
const allRules = getAllRuleNames(structure);
|
|
1838
|
+
const { match, ambiguous } = fuzzyMatch(lower, [...allRules, ...specialCommands], commandLabels);
|
|
1839
|
+
if (match && specialCommands.includes(match)) {
|
|
1840
|
+
yield handleCommand(match);
|
|
1841
|
+
return;
|
|
1842
|
+
}
|
|
1843
|
+
if (!match && ambiguous.length > 0) {
|
|
1844
|
+
const formatted = ambiguous.map((r) => formatRule(r, commandLabels));
|
|
1845
|
+
addResponse(`Did you mean: ${formatted.join(", ")}?`);
|
|
1846
|
+
return;
|
|
1847
|
+
}
|
|
1848
|
+
if (!match) {
|
|
1849
|
+
if (llm) {
|
|
1850
|
+
const response = yield askLLM(trimmed);
|
|
1851
|
+
if (response !== null)
|
|
1852
|
+
return;
|
|
1853
|
+
}
|
|
1854
|
+
const llmHint = llm ? " Enter an API key above to ask questions about the data." : "";
|
|
1855
|
+
addResponse(`Unknown command "${trimmed}". Type "help" for available commands.` + llmHint);
|
|
1856
|
+
return;
|
|
1857
|
+
}
|
|
1858
|
+
const direction = match;
|
|
1859
|
+
const label = commandLabels[direction] || direction;
|
|
1860
|
+
if (direction === "exit") {
|
|
1861
|
+
currentNodeId = null;
|
|
1862
|
+
if (onExit)
|
|
1863
|
+
onExit();
|
|
1864
|
+
addResponse('Exited the structure. Type "enter" to re-enter.');
|
|
1865
|
+
return;
|
|
1866
|
+
}
|
|
1867
|
+
const nextNode = inputHandler.move(currentNodeId, direction);
|
|
1868
|
+
if (nextNode) {
|
|
1869
|
+
currentNodeId = nextNode.id;
|
|
1870
|
+
if (onNavigate)
|
|
1871
|
+
onNavigate(nextNode);
|
|
1872
|
+
addResponse(`${label}: ${describeNode2(nextNode)}`);
|
|
1873
|
+
} else {
|
|
1874
|
+
addResponse(`Cannot move "${direction}" from here.`);
|
|
1875
|
+
}
|
|
1876
|
+
});
|
|
1877
|
+
formEl.addEventListener("submit", (e) => __async(void 0, null, function* () {
|
|
1878
|
+
e.preventDefault();
|
|
1879
|
+
const value = inputEl.value.trim();
|
|
1880
|
+
if (value) {
|
|
1881
|
+
history.push(value);
|
|
1882
|
+
historyIndex = -1;
|
|
1883
|
+
}
|
|
1884
|
+
yield handleCommand(inputEl.value);
|
|
1885
|
+
inputEl.value = "";
|
|
1886
|
+
inputEl.focus();
|
|
1887
|
+
}));
|
|
1888
|
+
return {
|
|
1889
|
+
destroy() {
|
|
1890
|
+
rootEl.removeChild(chatEl);
|
|
1891
|
+
},
|
|
1892
|
+
getCurrentNode() {
|
|
1893
|
+
return currentNodeId ? structure.nodes[currentNodeId] || null : null;
|
|
1894
|
+
}
|
|
1895
|
+
};
|
|
1896
|
+
};
|
|
1897
|
+
|
|
1335
1898
|
// src/index.ts
|
|
1336
|
-
var src_default = { structure: structure_default, input: input_default, rendering: rendering_default };
|
|
1899
|
+
var src_default = { structure: structure_default, input: input_default, rendering: rendering_default, textChat: text_chat_default };
|
|
1337
1900
|
export {
|
|
1338
1901
|
src_default as default
|
|
1339
1902
|
};
|