data-navigator 2.2.3 → 2.3.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/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?.parentOptions?.addLevel0) {
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] = { ...level0, dimensionLevel: 0 };
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?.filterFunction === "function" ? dim.operations.filterFunction(d, dim) : true;
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?.compressSparseDivisions || false,
444
- sortFunction: dim.operations?.sortFunction || void 0
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?.divisionNodeIds === "function" ? dim.divisionOptions.divisionNodeIds(dim.dimensionKey, value, i) : createValidId(dimension.nodeId + "_" + value);
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?.sortFunction || void 0,
515
+ sortFunction: ((_e = dim.divisionOptions) == null ? void 0 : _e.sortFunction) || void 0,
474
516
  values: {}
475
517
  };
476
- let divisionRenderId = typeof dim.divisionOptions?.divisionRenderIds === "function" ? dim.divisionOptions.divisionRenderIds(dim.dimensionKey, value, i) : divisionId;
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: { ...targetDivision },
484
- renderingStrategy: dim.divisionOptions?.renderingStrategy || "singleSquare"
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?.sortFunction || void 0,
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
- return typeof dimension.operations?.sortFunction === "function" ? dimension.operations.sortFunction(a[1], b[1], dimension) : a[1][s] - b[1][s];
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?.divisionNodeIds === "function" ? dimension.divisionOptions.divisionNodeIds(s, i, i) : dimension.nodeId + "_" + i;
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?.sortFunction || void 0,
583
+ sortFunction: ((_b2 = dimension.divisionOptions) == null ? void 0 : _b2.sortFunction) || void 0,
540
584
  values: {}
541
585
  };
542
- let divisionRenderId = typeof dimension.divisionOptions?.divisionRenderIds === "function" ? dimension.divisionOptions.divisionRenderIds(s, i, i) : divisionId;
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?.renderingStrategy || "singleSquare"
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?.sortFunction === "function") {
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] = { ...division.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?.parentOptions?.level1Options?.order;
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?.parentOptions || {};
663
- let extents = po.level1Options?.behavior?.extents || "terminal";
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?.navigationRules?.parent_child || ["parent", "child"] : [];
666
- let siblingRules = po.level1Options?.navigationRules?.sibling_sibling || ["left", "right"];
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?.childmostNavigation || "within";
705
- const matchByIndex = (i, _a, _b, c) => {
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?.childmostMatching ? dimension.behavior?.childmostMatching : matchByIndex;
709
- let extents2 = dimension.behavior?.extents || "circular";
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(
@@ -758,7 +804,7 @@ var buildEdges = (options, nodes, dimensions) => {
758
804
  "source"
759
805
  );
760
806
  let i = 0;
761
- if (valueKeys.length > 1) {
807
+ if (valueKeys.length >= 1) {
762
808
  valueKeys.forEach((vk) => {
763
809
  let v = division.values[vk];
764
810
  const id = typeof options.idKey === "function" ? options.idKey(v) : options.idKey;
@@ -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?.length) {
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] = { ...importedRules[k1] };
951
+ used[k1] = __spreadValues({}, importedRules[k1]);
904
952
  k1Assigned = true;
905
953
  }
906
954
  if (k2 && (importedRules[k2] || used[k2])) {
907
- used[k2] = { ...importedRules[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 = { ...GenericFullNavigationRules[r] };
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?.parentOptions?.addLevel0) {
975
- let rules2 = options.dimensions.parentOptions.level1Options?.navigationRules?.parent_child || [
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 = { ...needsKeys };
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: { ...NodeElementDefaults.spatialProperties },
1146
- semantics: { ...NodeElementDefaults.semantics },
1147
- parentSemantics: { ...NodeElementDefaults.parentSemantics },
1148
- existingElement: { ...NodeElementDefaults.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 ? { ...defaults.spatialProperties, ...options.defaults.spatialProperties } : defaults.spatialProperties;
1153
- defaults.semantics = options.defaults.semantics ? { ...defaults.semantics, ...options.defaults.semantics } : defaults.semantics;
1154
- defaults.parentSemantics = options.defaults.parentSemantics ? { ...defaults.parentSemantics, ...options.defaults.parentSemantics } : defaults.parentSemantics;
1155
- defaults.existingElement = options.defaults.existingElement ? { ...defaults.existingElement, ...options.defaults.existingElement } : 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?.include) {
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?.callbacks?.focus) {
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?.callbacks?.blur) {
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?.[subprop] : existingSpatialProperties[subprop];
1245
- const s2 = defaults[prop]?.[subprop];
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,510 @@ 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 levenshtein = (a, b) => {
1442
+ const m = a.length;
1443
+ const n = b.length;
1444
+ const dp = Array(n + 1);
1445
+ for (let j = 0; j <= n; j++)
1446
+ dp[j] = j;
1447
+ for (let i = 1; i <= m; i++) {
1448
+ let prev = dp[0];
1449
+ dp[0] = i;
1450
+ for (let j = 1; j <= n; j++) {
1451
+ const temp = dp[j];
1452
+ dp[j] = a[i - 1] === b[j - 1] ? prev : 1 + Math.min(prev, dp[j], dp[j - 1]);
1453
+ prev = temp;
1454
+ }
1455
+ }
1456
+ return dp[n];
1457
+ };
1458
+ var maxTypoDistance = (len) => len <= 4 ? 1 : 2;
1459
+ var fuzzyMatch = (input, candidates, labels = {}) => {
1460
+ const lower = input.toLowerCase().trim();
1461
+ const exactName = candidates.find((c) => c.toLowerCase() === lower);
1462
+ if (exactName)
1463
+ return { match: exactName, ambiguous: [] };
1464
+ const exactLabel = candidates.find(
1465
+ (c) => labels[c] && labels[c].toLowerCase() === lower
1466
+ );
1467
+ if (exactLabel)
1468
+ return { match: exactLabel, ambiguous: [] };
1469
+ const namePrefix = candidates.filter((c) => c.toLowerCase().startsWith(lower));
1470
+ if (namePrefix.length === 1)
1471
+ return { match: namePrefix[0], ambiguous: [] };
1472
+ const labelMatches = candidates.filter((c) => {
1473
+ if (!labels[c])
1474
+ return false;
1475
+ const labelLower = labels[c].toLowerCase();
1476
+ if (labelLower.startsWith(lower))
1477
+ return true;
1478
+ return labelLower.split(/\s+/).some((word) => word.startsWith(lower));
1479
+ });
1480
+ const combined = /* @__PURE__ */ new Set([...namePrefix, ...labelMatches]);
1481
+ const all = Array.from(combined);
1482
+ if (all.length === 1)
1483
+ return { match: all[0], ambiguous: [] };
1484
+ if (all.length > 1)
1485
+ return { match: null, ambiguous: all };
1486
+ const threshold = maxTypoDistance(lower.length);
1487
+ const typoMatches = [];
1488
+ for (let i = 0; i < candidates.length; i++) {
1489
+ const c = candidates[i];
1490
+ const nameDist = levenshtein(lower, c.toLowerCase());
1491
+ if (nameDist <= threshold) {
1492
+ typoMatches.push({ candidate: c, dist: nameDist });
1493
+ continue;
1494
+ }
1495
+ if (labels[c]) {
1496
+ const words = labels[c].toLowerCase().split(/\s+/);
1497
+ for (let w = 0; w < words.length; w++) {
1498
+ if (levenshtein(lower, words[w]) <= threshold) {
1499
+ typoMatches.push({ candidate: c, dist: levenshtein(lower, words[w]) });
1500
+ break;
1501
+ }
1502
+ }
1503
+ }
1504
+ }
1505
+ if (typoMatches.length === 1)
1506
+ return { match: typoMatches[0].candidate, ambiguous: [] };
1507
+ if (typoMatches.length > 1) {
1508
+ typoMatches.sort((a, b) => a.dist - b.dist);
1509
+ if (typoMatches[0].dist < typoMatches[1].dist) {
1510
+ return { match: typoMatches[0].candidate, ambiguous: [] };
1511
+ }
1512
+ return { match: null, ambiguous: typoMatches.map((t) => t.candidate) };
1513
+ }
1514
+ return { match: null, ambiguous: [] };
1515
+ };
1516
+ var formatRule = (ruleName, labels) => {
1517
+ if (labels[ruleName])
1518
+ return `${labels[ruleName]} (${ruleName})`;
1519
+ return ruleName;
1520
+ };
1521
+ var searchNodes = (query, structure, describeFn, limit = 10) => {
1522
+ const lower = query.toLowerCase();
1523
+ const results = [];
1524
+ const nodeIds = Object.keys(structure.nodes);
1525
+ for (let i = 0; i < nodeIds.length && results.length < limit; i++) {
1526
+ const nodeId = nodeIds[i];
1527
+ const node = structure.nodes[nodeId];
1528
+ let matched = false;
1529
+ if (node.data && !matched) {
1530
+ const dataKeys = Object.keys(node.data);
1531
+ for (let j = 0; j < dataKeys.length && !matched; j++) {
1532
+ const val = node.data[dataKeys[j]];
1533
+ if (val != null && typeof val !== "object" && String(val).toLowerCase().includes(lower)) {
1534
+ matched = true;
1535
+ }
1536
+ }
1537
+ }
1538
+ if (!matched && node.derivedNode && node.derivedNode.toLowerCase().includes(lower)) {
1539
+ matched = true;
1540
+ }
1541
+ if (!matched && nodeId.toLowerCase().includes(lower)) {
1542
+ matched = true;
1543
+ }
1544
+ if (matched) {
1545
+ results.push({ nodeId, description: describeFn(node) });
1546
+ }
1547
+ }
1548
+ return results;
1549
+ };
1550
+ var text_chat_default = (options) => {
1551
+ var _a;
1552
+ const {
1553
+ structure,
1554
+ container,
1555
+ entryPoint,
1556
+ describeNode: describeNode2 = defaultDescribeNode,
1557
+ commandLabels = {},
1558
+ onNavigate,
1559
+ onExit,
1560
+ llm,
1561
+ data
1562
+ } = options;
1563
+ const rootEl = typeof container === "string" ? document.getElementById(container) : container;
1564
+ if (!rootEl) {
1565
+ throw new Error(`textChat: container "${container}" not found`);
1566
+ }
1567
+ const resolvedEntryPoint = entryPoint || (structure.dimensions ? (_a = structure.dimensions[Object.keys(structure.dimensions)[0]]) == null ? void 0 : _a.nodeId : Object.keys(structure.nodes)[0]);
1568
+ const inputHandler = input_default({
1569
+ structure,
1570
+ navigationRules: structure.navigationRules || {},
1571
+ entryPoint: resolvedEntryPoint
1572
+ });
1573
+ let currentNodeId = null;
1574
+ const uid = Math.random().toString(36).slice(2, 8);
1575
+ const history = [];
1576
+ let historyIndex = -1;
1577
+ let pendingChoices = null;
1578
+ const llmHistory = [];
1579
+ const buildSystemPrompt = () => {
1580
+ let prompt = "You are a data assistant helping a user explore a dataset through a text-based navigation interface.\n\n";
1581
+ if (data && data.length > 0) {
1582
+ const columns = Object.keys(data[0]);
1583
+ const sampleRows = data.slice(0, 3).map((r) => JSON.stringify(r)).join("\n ");
1584
+ prompt += `DATASET SUMMARY:
1585
+ - Columns: ${columns.join(", ")}
1586
+ - Rows: ${data.length}
1587
+ - Sample (first 3):
1588
+ ${sampleRows}
1589
+
1590
+ `;
1591
+ prompt += "FULL DATASET (JSON):\n" + JSON.stringify(data) + "\n\n";
1592
+ }
1593
+ if (currentNodeId) {
1594
+ const node = structure.nodes[currentNodeId];
1595
+ prompt += `CURRENT POSITION: ${node ? describeNode2(node) : currentNodeId}
1596
+
1597
+ `;
1598
+ } else {
1599
+ prompt += "CURRENT POSITION: Not yet navigated into the structure.\n\n";
1600
+ }
1601
+ 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";
1602
+ 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";
1603
+ 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.';
1604
+ return prompt;
1605
+ };
1606
+ const chatEl = document.createElement("div");
1607
+ chatEl.className = "dn-text-chat";
1608
+ const logEl = document.createElement("div");
1609
+ logEl.className = "dn-text-chat-log";
1610
+ logEl.setAttribute("role", "log");
1611
+ logEl.setAttribute("aria-live", "polite");
1612
+ chatEl.appendChild(logEl);
1613
+ const controlsEl = document.createElement("div");
1614
+ controlsEl.className = "dn-text-chat-controls";
1615
+ const announceLabel = document.createElement("label");
1616
+ const announceCheckbox = document.createElement("input");
1617
+ announceCheckbox.type = "checkbox";
1618
+ announceCheckbox.checked = true;
1619
+ announceCheckbox.addEventListener("change", () => {
1620
+ logEl.setAttribute("aria-live", announceCheckbox.checked ? "polite" : "off");
1621
+ });
1622
+ announceLabel.appendChild(announceCheckbox);
1623
+ announceLabel.appendChild(document.createTextNode(" Automatically announce to screen readers"));
1624
+ controlsEl.appendChild(announceLabel);
1625
+ chatEl.appendChild(controlsEl);
1626
+ const formEl = document.createElement("form");
1627
+ formEl.className = "dn-text-chat-form";
1628
+ const inputLabel = document.createElement("label");
1629
+ inputLabel.setAttribute("for", `dn-text-chat-input-${uid}`);
1630
+ inputLabel.className = "dn-text-chat-sr-only";
1631
+ inputLabel.textContent = "Navigation command";
1632
+ const inputEl = document.createElement("input");
1633
+ inputEl.type = "text";
1634
+ inputEl.id = `dn-text-chat-input-${uid}`;
1635
+ inputEl.autocomplete = "off";
1636
+ inputEl.setAttribute("placeholder", "Type a command...");
1637
+ const submitBtn = document.createElement("button");
1638
+ submitBtn.type = "submit";
1639
+ submitBtn.textContent = "Send";
1640
+ formEl.appendChild(inputLabel);
1641
+ formEl.appendChild(inputEl);
1642
+ formEl.appendChild(submitBtn);
1643
+ chatEl.appendChild(formEl);
1644
+ rootEl.appendChild(chatEl);
1645
+ let savedInput = "";
1646
+ inputEl.addEventListener("keydown", (e) => {
1647
+ if (e.key === "ArrowUp") {
1648
+ e.preventDefault();
1649
+ if (history.length === 0)
1650
+ return;
1651
+ if (historyIndex === -1) {
1652
+ savedInput = inputEl.value;
1653
+ historyIndex = history.length - 1;
1654
+ } else if (historyIndex > 0) {
1655
+ historyIndex--;
1656
+ }
1657
+ inputEl.value = history[historyIndex];
1658
+ } else if (e.key === "ArrowDown") {
1659
+ e.preventDefault();
1660
+ if (historyIndex === -1)
1661
+ return;
1662
+ if (historyIndex < history.length - 1) {
1663
+ historyIndex++;
1664
+ inputEl.value = history[historyIndex];
1665
+ } else {
1666
+ historyIndex = -1;
1667
+ inputEl.value = savedInput;
1668
+ }
1669
+ }
1670
+ });
1671
+ const addMessage = (text, className) => {
1672
+ const msg = document.createElement("div");
1673
+ msg.className = `dn-text-chat-message ${className}`;
1674
+ msg.textContent = text;
1675
+ logEl.appendChild(msg);
1676
+ logEl.scrollTop = logEl.scrollHeight;
1677
+ };
1678
+ const addSystemMessage = (text) => addMessage(text, "dn-text-chat-system");
1679
+ const addEcho = (text) => addMessage(`> ${text}`, "dn-text-chat-input-echo");
1680
+ const addResponse = (text) => addMessage(text, "dn-text-chat-response");
1681
+ const addResponseWithList = (intro, items) => {
1682
+ const wrapper = document.createElement("div");
1683
+ wrapper.className = "dn-text-chat-message dn-text-chat-response";
1684
+ const p = document.createElement("span");
1685
+ p.textContent = intro;
1686
+ wrapper.appendChild(p);
1687
+ const ol = document.createElement("ol");
1688
+ ol.className = "dn-text-chat-choices";
1689
+ items.forEach((item) => {
1690
+ const li = document.createElement("li");
1691
+ li.textContent = item;
1692
+ ol.appendChild(li);
1693
+ });
1694
+ wrapper.appendChild(ol);
1695
+ logEl.appendChild(wrapper);
1696
+ logEl.scrollTop = logEl.scrollHeight;
1697
+ };
1698
+ const askLLM = (question) => __async(void 0, null, function* () {
1699
+ const systemMsg = { role: "system", content: buildSystemPrompt() };
1700
+ llmHistory.push({ role: "user", content: question });
1701
+ const thinkingMsg = document.createElement("div");
1702
+ thinkingMsg.className = "dn-text-chat-message dn-text-chat-llm-thinking";
1703
+ thinkingMsg.textContent = "Thinking...";
1704
+ logEl.appendChild(thinkingMsg);
1705
+ logEl.scrollTop = logEl.scrollHeight;
1706
+ try {
1707
+ const response = yield llm([systemMsg, ...llmHistory]);
1708
+ logEl.removeChild(thinkingMsg);
1709
+ if (response === null) {
1710
+ llmHistory.pop();
1711
+ return null;
1712
+ }
1713
+ llmHistory.push({ role: "assistant", content: response });
1714
+ addResponse(response);
1715
+ return response;
1716
+ } catch (err) {
1717
+ logEl.removeChild(thinkingMsg);
1718
+ llmHistory.pop();
1719
+ addResponse(`Error: ${err.message || "Could not get a response."}`);
1720
+ return "";
1721
+ }
1722
+ });
1723
+ if (llm) {
1724
+ addSystemMessage('Text navigation ready. Type "enter" to begin navigating, "help" for commands, or ask a question about the data.');
1725
+ 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.');
1726
+ } else {
1727
+ addSystemMessage('Text navigation ready. Type "enter" to begin or "help" for available commands.');
1728
+ }
1729
+ const specialCommands = ["enter", "help", "more", "more help", "clear"];
1730
+ const moveToNode = (nodeId) => {
1731
+ const node = inputHandler.moveTo(nodeId);
1732
+ if (node) {
1733
+ currentNodeId = node.id;
1734
+ if (onNavigate)
1735
+ onNavigate(node);
1736
+ addResponse(`Moved to: ${describeNode2(node)}`);
1737
+ } else {
1738
+ addResponse("Could not move to that node.");
1739
+ }
1740
+ };
1741
+ const handleCommand = (raw) => __async(void 0, null, function* () {
1742
+ const trimmed = raw.trim();
1743
+ if (!trimmed)
1744
+ return;
1745
+ addEcho(trimmed);
1746
+ const lower = trimmed.toLowerCase();
1747
+ if (pendingChoices) {
1748
+ const num = parseInt(trimmed, 10);
1749
+ if (!isNaN(num) && num >= 1 && num <= pendingChoices.length) {
1750
+ const choice = pendingChoices[num - 1];
1751
+ pendingChoices = null;
1752
+ moveToNode(choice.nodeId);
1753
+ return;
1754
+ }
1755
+ pendingChoices = null;
1756
+ }
1757
+ if (lower === "clear") {
1758
+ logEl.innerHTML = "";
1759
+ addSystemMessage('Chat cleared. Type "help" for available commands.');
1760
+ return;
1761
+ }
1762
+ if (lower === "enter") {
1763
+ if (currentNodeId) {
1764
+ addResponse('Already in the structure. Type "help" to see available commands.');
1765
+ return;
1766
+ }
1767
+ const entryNode = inputHandler.enter();
1768
+ if (!entryNode) {
1769
+ addResponse("Could not enter the structure. No entry point found.");
1770
+ return;
1771
+ }
1772
+ currentNodeId = entryNode.id;
1773
+ if (onNavigate)
1774
+ onNavigate(entryNode);
1775
+ addResponse(`Entered: ${describeNode2(entryNode)}`);
1776
+ return;
1777
+ }
1778
+ if (lower === "help") {
1779
+ const llmHint = llm ? " You can also type any question about the data." : "";
1780
+ if (!currentNodeId) {
1781
+ addResponse(
1782
+ 'Not yet in the structure. Type "enter" to begin navigating, or "move to <search>" to jump to a node.' + llmHint
1783
+ );
1784
+ } else {
1785
+ const node = structure.nodes[currentNodeId];
1786
+ const available = getAvailableRules(currentNodeId, node, structure);
1787
+ const formatted = available.map((r) => formatRule(r, commandLabels));
1788
+ addResponse(`Available: ${formatted.join(", ")}, move to <search>.` + llmHint);
1789
+ }
1790
+ return;
1791
+ }
1792
+ if (lower.startsWith("move to ")) {
1793
+ const query = trimmed.slice("move to ".length).trim();
1794
+ if (!query) {
1795
+ addResponse("Usage: move to <search term>");
1796
+ return;
1797
+ }
1798
+ const results = searchNodes(query, structure, describeNode2);
1799
+ if (results.length === 0) {
1800
+ addResponse(`No nodes found matching "${query}".`);
1801
+ } else if (results.length === 1) {
1802
+ moveToNode(results[0].nodeId);
1803
+ } else {
1804
+ pendingChoices = results;
1805
+ addResponseWithList(
1806
+ `Found ${results.length} matches. Type a number to move there:`,
1807
+ results.map((r) => r.description)
1808
+ );
1809
+ }
1810
+ return;
1811
+ }
1812
+ if (lower === "more" || lower === "more help") {
1813
+ const allRules2 = getAllRuleNames(structure);
1814
+ const formatted = allRules2.map((r) => formatRule(r, commandLabels));
1815
+ addResponse(`All navigation rules: ${formatted.join(", ")}.`);
1816
+ return;
1817
+ }
1818
+ if (!currentNodeId) {
1819
+ if (llm) {
1820
+ const response = yield askLLM(trimmed);
1821
+ if (response !== null)
1822
+ return;
1823
+ }
1824
+ const llmHint = llm ? " Enter an API key above to ask questions about the data." : "";
1825
+ addResponse('Type "enter" to begin navigating the structure, or "move to <search>" to jump to a node.' + llmHint);
1826
+ return;
1827
+ }
1828
+ const allRules = getAllRuleNames(structure);
1829
+ const { match, ambiguous } = fuzzyMatch(lower, [...allRules, ...specialCommands], commandLabels);
1830
+ if (match && specialCommands.includes(match)) {
1831
+ yield handleCommand(match);
1832
+ return;
1833
+ }
1834
+ if (!match && ambiguous.length > 0) {
1835
+ const formatted = ambiguous.map((r) => formatRule(r, commandLabels));
1836
+ addResponse(`Did you mean: ${formatted.join(", ")}?`);
1837
+ return;
1838
+ }
1839
+ if (!match) {
1840
+ if (llm) {
1841
+ const response = yield askLLM(trimmed);
1842
+ if (response !== null)
1843
+ return;
1844
+ }
1845
+ const llmHint = llm ? " Enter an API key above to ask questions about the data." : "";
1846
+ addResponse(`Unknown command "${trimmed}". Type "help" for available commands.` + llmHint);
1847
+ return;
1848
+ }
1849
+ const direction = match;
1850
+ const label = commandLabels[direction] || direction;
1851
+ if (direction === "exit") {
1852
+ currentNodeId = null;
1853
+ if (onExit)
1854
+ onExit();
1855
+ addResponse('Exited the structure. Type "enter" to re-enter.');
1856
+ return;
1857
+ }
1858
+ const nextNode = inputHandler.move(currentNodeId, direction);
1859
+ if (nextNode) {
1860
+ currentNodeId = nextNode.id;
1861
+ if (onNavigate)
1862
+ onNavigate(nextNode);
1863
+ addResponse(`${label}: ${describeNode2(nextNode)}`);
1864
+ } else {
1865
+ addResponse(`Cannot move "${direction}" from here.`);
1866
+ }
1867
+ });
1868
+ formEl.addEventListener("submit", (e) => __async(void 0, null, function* () {
1869
+ e.preventDefault();
1870
+ const value = inputEl.value.trim();
1871
+ if (value) {
1872
+ history.push(value);
1873
+ historyIndex = -1;
1874
+ }
1875
+ yield handleCommand(inputEl.value);
1876
+ inputEl.value = "";
1877
+ inputEl.focus();
1878
+ }));
1879
+ return {
1880
+ destroy() {
1881
+ rootEl.removeChild(chatEl);
1882
+ },
1883
+ getCurrentNode() {
1884
+ return currentNodeId ? structure.nodes[currentNodeId] || null : null;
1885
+ }
1886
+ };
1887
+ };
1888
+
1335
1889
  // src/index.ts
1336
- var src_default = { structure: structure_default, input: input_default, rendering: rendering_default };
1890
+ var src_default = { structure: structure_default, input: input_default, rendering: rendering_default, textChat: text_chat_default };
1337
1891
  export {
1338
1892
  src_default as default
1339
1893
  };