data-navigator 2.4.0 → 3.0.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.cjs CHANGED
@@ -32,6 +32,28 @@ var __copyProps = (to, from, except, desc) => {
32
32
  return to;
33
33
  };
34
34
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
35
+ var __accessCheck = (obj, member, msg) => {
36
+ if (!member.has(obj))
37
+ throw TypeError("Cannot " + msg);
38
+ };
39
+ var __privateGet = (obj, member, getter) => {
40
+ __accessCheck(obj, member, "read from private field");
41
+ return getter ? getter.call(obj) : member.get(obj);
42
+ };
43
+ var __privateAdd = (obj, member, value) => {
44
+ if (member.has(obj))
45
+ throw TypeError("Cannot add the same private member more than once");
46
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
47
+ };
48
+ var __privateSet = (obj, member, value, setter) => {
49
+ __accessCheck(obj, member, "write to private field");
50
+ setter ? setter.call(obj, value) : member.set(obj, value);
51
+ return value;
52
+ };
53
+ var __privateMethod = (obj, member, method) => {
54
+ __accessCheck(obj, member, "access private method");
55
+ return method;
56
+ };
35
57
  var __async = (__this, __arguments, generator) => {
36
58
  return new Promise((resolve, reject) => {
37
59
  var fulfilled = (value) => {
@@ -56,7 +78,17 @@ var __async = (__this, __arguments, generator) => {
56
78
  // src/index.ts
57
79
  var src_exports = {};
58
80
  __export(src_exports, {
59
- default: () => src_default
81
+ boundingRectPath: () => boundingRectPath,
82
+ convexHullOfCircles: () => convexHullOfCircles,
83
+ convexHullOfRects: () => convexHullOfRects,
84
+ convexHullPath: () => convexHullPath,
85
+ createValidId: () => createValidId,
86
+ default: () => src_default,
87
+ describeNode: () => describeNode,
88
+ expandHull: () => expandHull,
89
+ grahamScan: () => grahamScan,
90
+ offsetLinePath: () => offsetLinePath,
91
+ unionOfRectPaths: () => unionOfRectPaths
60
92
  });
61
93
  module.exports = __toCommonJS(src_exports);
62
94
 
@@ -77,8 +109,8 @@ var defaultKeyBindings = {
77
109
  ArrowDown: "down",
78
110
  Period: "forward",
79
111
  Comma: "backward",
80
- Escape: "parent",
81
- Enter: "child"
112
+ Escape: "drill-out",
113
+ Enter: "drill-in"
82
114
  };
83
115
  var TypicallyUnreservedKeys = ["KeyW", "KeyJ", "LeftBracket", "RightBracket", "Slash", "Backslash"];
84
116
  var TypicallyUnreservedKeyPairs = [
@@ -102,11 +134,11 @@ var GenericFullNavigationRules = {
102
134
  key: "ArrowDown",
103
135
  direction: "target"
104
136
  },
105
- child: {
137
+ "drill-in": {
106
138
  key: "Enter",
107
139
  direction: "target"
108
140
  },
109
- parent: {
141
+ "drill-out": {
110
142
  key: "Backspace",
111
143
  direction: "source"
112
144
  },
@@ -162,11 +194,11 @@ var GenericLimitedNavigationRules = {
162
194
  key: "ArrowUp",
163
195
  direction: "source"
164
196
  },
165
- child: {
197
+ "drill-in": {
166
198
  key: "Enter",
167
199
  direction: "target"
168
200
  },
169
- parent: {
201
+ "drill-out": {
170
202
  key: "Backspace",
171
203
  direction: "source"
172
204
  },
@@ -209,6 +241,26 @@ var NodeElementDefaults = {
209
241
  spatialProperties: void 0
210
242
  }
211
243
  };
244
+ var GenericNavigationRuleCommands = {
245
+ "drill-in": { label: "Enter", description: "Drill in" },
246
+ "drill-out": { label: "Backspace", description: "Drill out" },
247
+ exit: { label: "Esc", description: "Exit" },
248
+ left: { label: "\u2190", description: "Previous data point" },
249
+ right: { label: "\u2192", description: "Next data point" },
250
+ up: { label: "\u2191", description: "Previous data point" },
251
+ down: { label: "\u2193", description: "Next data point" },
252
+ backward: { label: ",", description: "Move backward" },
253
+ forward: { label: ".", description: "Move forward" },
254
+ previous: { label: ";", description: "Previous" },
255
+ next: { label: "'", description: "Next" },
256
+ undo: { label: "Z", description: "Undo" },
257
+ help: { label: "Y", description: "Help" },
258
+ legend: { label: "L", description: "Legend" }
259
+ };
260
+ var commandsTableDefaultColumns = [
261
+ { label: "Command", id: "description" },
262
+ { label: "Key", id: "label" }
263
+ ];
212
264
 
213
265
  // src/utilities.ts
214
266
  var describeNode = (d, descriptionOptions) => {
@@ -223,6 +275,12 @@ var describeNode = (d, descriptionOptions) => {
223
275
  var createValidId = (s) => {
224
276
  return "_" + s.replace(/[^a-zA-Z0-9_-]+/g, "_");
225
277
  };
278
+ function getGenericCommandsFromNavRules(navigationRules) {
279
+ if (!navigationRules) {
280
+ return [];
281
+ }
282
+ return Object.keys(navigationRules).map((navId) => GenericNavigationRuleCommands[navId]).filter(Boolean);
283
+ }
226
284
 
227
285
  // src/structure.ts
228
286
  var structure_default = (options) => {
@@ -299,7 +357,7 @@ var buildNodeStructureFromVegaLite = (options) => {
299
357
  edges[firstChildEdge] = {
300
358
  source: node.id,
301
359
  target: firstChildId,
302
- navigationRules: ["parent", "child"]
360
+ navigationRules: ["drill-out", "drill-in"]
303
361
  };
304
362
  }
305
363
  }
@@ -312,7 +370,7 @@ var buildNodeStructureFromVegaLite = (options) => {
312
370
  edges[parentEdge] = {
313
371
  source: parentId,
314
372
  target: node.id,
315
- navigationRules: ["parent", "child"]
373
+ navigationRules: ["drill-out", "drill-in"]
316
374
  };
317
375
  }
318
376
  }
@@ -513,7 +571,7 @@ var scaffoldDimensions = (options, nodes) => {
513
571
  },
514
572
  navigationRules: dim.navigationRules || {
515
573
  sibling_sibling: rules.length ? [...rules.shift()] : ["previous_" + dim.dimensionKey, "next_" + dim.dimensionKey],
516
- parent_child: ["parent_" + dim.dimensionKey, "child"]
574
+ parent_child: ["drill-out_" + dim.dimensionKey, "drill-in"]
517
575
  }
518
576
  };
519
577
  nodes[id2] = {
@@ -626,7 +684,8 @@ var scaffoldDimensions = (options, nodes) => {
626
684
  let node = values[valueKeys[index]];
627
685
  let value = node[s];
628
686
  if (value <= i) {
629
- dimension.divisions[divisionId].values[node.id] = node;
687
+ const leafId = typeof options.idKey === "function" ? options.idKey(node) : node[options.idKey];
688
+ dimension.divisions[divisionId].values[leafId] = node;
630
689
  index++;
631
690
  } else {
632
691
  limit = true;
@@ -638,11 +697,12 @@ var scaffoldDimensions = (options, nodes) => {
638
697
  if (lastDivisionId && index < valueKeys.length) {
639
698
  while (index < valueKeys.length) {
640
699
  let node = values[valueKeys[index]];
641
- dimension.divisions[lastDivisionId].values[node.id] = node;
700
+ const leafId = typeof options.idKey === "function" ? options.idKey(node) : node[options.idKey];
701
+ dimension.divisions[lastDivisionId].values[leafId] = node;
642
702
  index++;
643
703
  }
644
704
  }
645
- delete divisions[s];
705
+ delete divisions[dimension.nodeId];
646
706
  }
647
707
  } else if (typeof ((_e = dimension.operations) == null ? void 0 : _e.sortFunction) === "function") {
648
708
  dimension.divisions = Object.fromEntries(
@@ -741,7 +801,7 @@ var buildEdges = (options, nodes, dimensions) => {
741
801
  let po = ((_d = options.dimensions) == null ? void 0 : _d.parentOptions) || {};
742
802
  let extents = ((_f = (_e = po.level1Options) == null ? void 0 : _e.behavior) == null ? void 0 : _f.extents) || "terminal";
743
803
  let level0 = po.addLevel0;
744
- let parentRules = level0 ? ((_h = (_g = po.level1Options) == null ? void 0 : _g.navigationRules) == null ? void 0 : _h.parent_child) || ["parent", "child"] : [];
804
+ let parentRules = level0 ? ((_h = (_g = po.level1Options) == null ? void 0 : _g.navigationRules) == null ? void 0 : _h.parent_child) || ["drill-out", "drill-in"] : [];
745
805
  let siblingRules = ((_j = (_i = po.level1Options) == null ? void 0 : _i.navigationRules) == null ? void 0 : _j.sibling_sibling) || ["left", "right"];
746
806
  let firstLevel1Node = typeof order[0] === "string" ? hasOrder ? nodes[order[0]] : nodes[dimensions[order[0]].nodeId] : order[0];
747
807
  if (level0) {
@@ -808,6 +868,22 @@ var buildEdges = (options, nodes, dimensions) => {
808
868
  "source"
809
869
  );
810
870
  }
871
+ const findNextNonEmptyDivIdx = (fromIdx) => {
872
+ for (let step = 1; step < divisionKeys.length; step++) {
873
+ const idx = (fromIdx + step) % divisionKeys.length;
874
+ if (Object.keys(dimension.divisions[divisionKeys[idx]].values).length > 0)
875
+ return idx;
876
+ }
877
+ return null;
878
+ };
879
+ const findPrevNonEmptyDivIdx = (fromIdx) => {
880
+ for (let step = 1; step < divisionKeys.length; step++) {
881
+ const idx = (fromIdx - step + divisionKeys.length) % divisionKeys.length;
882
+ if (Object.keys(dimension.divisions[divisionKeys[idx]].values).length > 0)
883
+ return idx;
884
+ }
885
+ return null;
886
+ };
811
887
  let j = 0;
812
888
  divisionKeys.forEach((d) => {
813
889
  let division = dimension.divisions[d];
@@ -859,22 +935,13 @@ var buildEdges = (options, nodes, dimensions) => {
859
935
  dimension.navigationRules.sibling_sibling
860
936
  );
861
937
  } else if (i === valueKeys.length - 1 && extents2 === "bridgedCousins") {
862
- if (j !== divisionKeys.length - 1) {
863
- const targetId = typeof options.idKey === "function" ? options.idKey(
864
- dimension.divisions[divisionKeys[j + 1]].values[valueKeys[0]]
865
- ) : options.idKey;
866
- createEdge(
867
- v[id],
868
- dimension.divisions[divisionKeys[j + 1]].values[valueKeys[0]][targetId],
869
- dimension.navigationRules.sibling_sibling
870
- );
871
- } else {
872
- const targetId = typeof options.idKey === "function" ? options.idKey(dimension.divisions[divisionKeys[0]].values[valueKeys[0]]) : options.idKey;
873
- createEdge(
874
- v[id],
875
- dimension.divisions[divisionKeys[0]].values[valueKeys[0]][targetId],
876
- dimension.navigationRules.sibling_sibling
877
- );
938
+ const nextIdx = findNextNonEmptyDivIdx(j);
939
+ if (nextIdx !== null) {
940
+ const nextDivValues = dimension.divisions[divisionKeys[nextIdx]].values;
941
+ const nextDivValueKeys = Object.keys(nextDivValues);
942
+ const targetDatum = nextDivValues[nextDivValueKeys[0]];
943
+ const targetId = typeof options.idKey === "function" ? options.idKey(targetDatum) : options.idKey;
944
+ createEdge(v[id], targetDatum[targetId], dimension.navigationRules.sibling_sibling);
878
945
  }
879
946
  } else if (i === valueKeys.length - 1 && extents2 === "bridgedCustom") {
880
947
  createEdge(
@@ -891,24 +958,13 @@ var buildEdges = (options, nodes, dimensions) => {
891
958
  );
892
959
  }
893
960
  if (!i && extents2 === "bridgedCousins") {
894
- if (j !== 0) {
895
- const targetId = typeof options.idKey === "function" ? options.idKey(
896
- dimension.divisions[divisionKeys[j - 1]].values[valueKeys[valueKeys.length - 1]]
897
- ) : options.idKey;
898
- createEdge(
899
- dimension.divisions[divisionKeys[j - 1]].values[valueKeys[valueKeys.length - 1]][targetId],
900
- v[id],
901
- dimension.navigationRules.sibling_sibling
902
- );
903
- } else {
904
- const targetId = typeof options.idKey === "function" ? options.idKey(
905
- dimension.divisions[divisionKeys[divisionKeys.length - 1]].values[valueKeys[valueKeys.length - 1]]
906
- ) : options.idKey;
907
- createEdge(
908
- dimension.divisions[divisionKeys[divisionKeys.length - 1]].values[valueKeys[valueKeys.length - 1]][targetId],
909
- v[id],
910
- dimension.navigationRules.sibling_sibling
911
- );
961
+ const prevIdx = findPrevNonEmptyDivIdx(j);
962
+ if (prevIdx !== null) {
963
+ const prevDivValues = dimension.divisions[divisionKeys[prevIdx]].values;
964
+ const prevDivValueKeys = Object.keys(prevDivValues);
965
+ const targetDatum = prevDivValues[prevDivValueKeys[prevDivValueKeys.length - 1]];
966
+ const targetId = typeof options.idKey === "function" ? options.idKey(targetDatum) : options.idKey;
967
+ createEdge(targetDatum[targetId], v[id], dimension.navigationRules.sibling_sibling);
912
968
  }
913
969
  } else if (!i && extents2 === "bridgedCustom") {
914
970
  createEdge(
@@ -1057,8 +1113,8 @@ var buildRules = (options, edges, dimensions) => {
1057
1113
  if (dimKeys.length) {
1058
1114
  if ((_b = (_a = options.dimensions) == null ? void 0 : _a.parentOptions) == null ? void 0 : _b.addLevel0) {
1059
1115
  let rules2 = ((_d = (_c = options.dimensions.parentOptions.level1Options) == null ? void 0 : _c.navigationRules) == null ? void 0 : _d.parent_child) || [
1060
- "parent",
1061
- "child"
1116
+ "drill-out",
1117
+ "drill-in"
1062
1118
  ];
1063
1119
  checkKeys(rules2[0], rules2[1]);
1064
1120
  }
@@ -1214,6 +1270,124 @@ var input_default = (options) => {
1214
1270
  return inputHandler;
1215
1271
  };
1216
1272
 
1273
+ // src/commands-table.ts
1274
+ var _commands, _columns, _kbdColumn, _connected, _render, render_fn;
1275
+ var CommandsTable = class extends HTMLElement {
1276
+ constructor() {
1277
+ super(...arguments);
1278
+ __privateAdd(this, _render);
1279
+ __privateAdd(this, _commands, []);
1280
+ __privateAdd(this, _columns, commandsTableDefaultColumns);
1281
+ __privateAdd(this, _kbdColumn, "label");
1282
+ __privateAdd(this, _connected, false);
1283
+ }
1284
+ static get observedAttributes() {
1285
+ return ["title"];
1286
+ }
1287
+ set commands(value) {
1288
+ __privateSet(this, _commands, value);
1289
+ if (!__privateGet(this, _connected))
1290
+ return;
1291
+ __privateMethod(this, _render, render_fn).call(this);
1292
+ }
1293
+ get commands() {
1294
+ return __privateGet(this, _commands);
1295
+ }
1296
+ set columns(value) {
1297
+ __privateSet(this, _columns, value);
1298
+ if (!__privateGet(this, _connected))
1299
+ return;
1300
+ __privateMethod(this, _render, render_fn).call(this);
1301
+ }
1302
+ get columns() {
1303
+ return __privateGet(this, _columns);
1304
+ }
1305
+ /** Column id whose cells are wrapped in <kbd>. Defaults to 'label'. Set to null to disable. */
1306
+ set kbdColumn(value) {
1307
+ __privateSet(this, _kbdColumn, value);
1308
+ if (!__privateGet(this, _connected))
1309
+ return;
1310
+ __privateMethod(this, _render, render_fn).call(this);
1311
+ }
1312
+ get kbdColumn() {
1313
+ return __privateGet(this, _kbdColumn);
1314
+ }
1315
+ attributeChangedCallback() {
1316
+ if (!__privateGet(this, _connected))
1317
+ return;
1318
+ __privateMethod(this, _render, render_fn).call(this);
1319
+ }
1320
+ connectedCallback() {
1321
+ __privateSet(this, _connected, true);
1322
+ __privateMethod(this, _render, render_fn).call(this);
1323
+ }
1324
+ disconnectedCallback() {
1325
+ __privateSet(this, _connected, false);
1326
+ }
1327
+ };
1328
+ _commands = new WeakMap();
1329
+ _columns = new WeakMap();
1330
+ _kbdColumn = new WeakMap();
1331
+ _connected = new WeakMap();
1332
+ _render = new WeakSet();
1333
+ render_fn = function() {
1334
+ this.replaceChildren();
1335
+ const headerCells = [];
1336
+ for (const column of __privateGet(this, _columns)) {
1337
+ const headerCell = document.createElement("th");
1338
+ headerCell.classList.add("dn-commands-table-th");
1339
+ headerCell.textContent = column.label;
1340
+ headerCells.push(headerCell);
1341
+ }
1342
+ const headerRow = document.createElement("tr");
1343
+ headerRow.classList.add("dn-commands-table-thead-tr");
1344
+ for (const headerCell of headerCells) {
1345
+ headerRow.appendChild(headerCell);
1346
+ }
1347
+ const thead = document.createElement("thead");
1348
+ thead.classList.add("dn-commands-table-thead");
1349
+ thead.appendChild(headerRow);
1350
+ const tbody = document.createElement("tbody");
1351
+ tbody.classList.add("dn-commands-table-tbody");
1352
+ for (const command of __privateGet(this, _commands)) {
1353
+ const rowCells = [];
1354
+ for (const column of __privateGet(this, _columns)) {
1355
+ const cellValue = command[column.id];
1356
+ const rowCell = document.createElement("td");
1357
+ rowCell.classList.add("dn-commands-table-td");
1358
+ if (__privateGet(this, _kbdColumn) !== null && column.id === __privateGet(this, _kbdColumn) && cellValue) {
1359
+ const kbd = document.createElement("kbd");
1360
+ kbd.classList.add("dn-commands-table-td-kbd");
1361
+ kbd.textContent = cellValue;
1362
+ rowCell.append(kbd);
1363
+ } else {
1364
+ rowCell.textContent = cellValue;
1365
+ }
1366
+ rowCells.push(rowCell);
1367
+ }
1368
+ const row = document.createElement("tr");
1369
+ row.classList.add("dn-commands-table-tbody-tr");
1370
+ for (const rowCell of rowCells) {
1371
+ row.appendChild(rowCell);
1372
+ }
1373
+ tbody.appendChild(row);
1374
+ }
1375
+ const table = document.createElement("table");
1376
+ table.classList.add("dn-commands-table");
1377
+ const title = this.getAttribute("title");
1378
+ if (title) {
1379
+ const caption = document.createElement("caption");
1380
+ caption.classList.add("dn-commands-table-caption");
1381
+ caption.textContent = title;
1382
+ table.appendChild(caption);
1383
+ } else {
1384
+ table.setAttribute("aria-label", "Commands table");
1385
+ }
1386
+ table.appendChild(thead);
1387
+ table.appendChild(tbody);
1388
+ this.appendChild(table);
1389
+ };
1390
+
1217
1391
  // src/rendering.ts
1218
1392
  var rendering_default = (options) => {
1219
1393
  const setActiveDescendant = (e) => {
@@ -1239,7 +1413,7 @@ var rendering_default = (options) => {
1239
1413
  defaults.existingElement = options.defaults.existingElement ? __spreadValues(__spreadValues({}, defaults.existingElement), options.defaults.existingElement) : defaults.existingElement;
1240
1414
  }
1241
1415
  renderer.initialize = () => {
1242
- var _a;
1416
+ var _a, _b;
1243
1417
  if (initialized) {
1244
1418
  console.error(
1245
1419
  `The renderer wrapper has already been initialized successfully, RenderingOptions.suffixId is: ${options.suffixId}. No further action was taken.`
@@ -1270,6 +1444,9 @@ var rendering_default = (options) => {
1270
1444
  if (options.root && options.root.height) {
1271
1445
  renderer.wrapper.style.height = options.root.height;
1272
1446
  }
1447
+ if ((_a = options.commandsElement) == null ? void 0 : _a.include) {
1448
+ renderer.initializeCommands(options.commandsElement);
1449
+ }
1273
1450
  if (options.entryButton && options.entryButton.include) {
1274
1451
  renderer.entryButton = document.createElement("button");
1275
1452
  renderer.entryButton.id = "dn-entry-button-" + options.suffixId;
@@ -1284,7 +1461,7 @@ var rendering_default = (options) => {
1284
1461
  renderer.wrapper.appendChild(renderer.entryButton);
1285
1462
  }
1286
1463
  renderer.root.appendChild(renderer.wrapper);
1287
- if ((_a = options.exitElement) == null ? void 0 : _a.include) {
1464
+ if ((_b = options.exitElement) == null ? void 0 : _b.include) {
1288
1465
  renderer.exitElement = document.createElement("div");
1289
1466
  renderer.exitElement.id = "dn-exit-" + options.suffixId;
1290
1467
  renderer.exitElement.classList.add("dn-exit-position");
@@ -1294,17 +1471,17 @@ var rendering_default = (options) => {
1294
1471
  renderer.exitElement.setAttribute("tabindex", "-1");
1295
1472
  renderer.exitElement.style.display = "none";
1296
1473
  renderer.exitElement.addEventListener("focus", (e) => {
1297
- var _a2, _b;
1474
+ var _a2, _b2;
1298
1475
  renderer.exitElement.style.display = "block";
1299
1476
  renderer.clearStructure();
1300
- if ((_b = (_a2 = options.exitElement) == null ? void 0 : _a2.callbacks) == null ? void 0 : _b.focus) {
1477
+ if ((_b2 = (_a2 = options.exitElement) == null ? void 0 : _a2.callbacks) == null ? void 0 : _b2.focus) {
1301
1478
  options.exitElement.callbacks.focus(e);
1302
1479
  }
1303
1480
  });
1304
1481
  renderer.exitElement.addEventListener("blur", (e) => {
1305
- var _a2, _b;
1482
+ var _a2, _b2;
1306
1483
  renderer.exitElement.style.display = "none";
1307
- if ((_b = (_a2 = options.exitElement) == null ? void 0 : _a2.callbacks) == null ? void 0 : _b.blur) {
1484
+ if ((_b2 = (_a2 = options.exitElement) == null ? void 0 : _a2.callbacks) == null ? void 0 : _b2.blur) {
1308
1485
  options.exitElement.callbacks.blur(e);
1309
1486
  }
1310
1487
  });
@@ -1417,6 +1594,31 @@ var rendering_default = (options) => {
1417
1594
  }
1418
1595
  });
1419
1596
  };
1597
+ renderer.initializeCommands = (commandOptions) => {
1598
+ const root = document.getElementById(commandOptions == null ? void 0 : commandOptions.rootId);
1599
+ if (!root) {
1600
+ console.error("Commands root element not found in document.");
1601
+ return;
1602
+ }
1603
+ const optionsCommands = commandOptions.commands;
1604
+ const genericCommandsFromRules = getGenericCommandsFromNavRules(commandOptions.navigationRules);
1605
+ const commands = optionsCommands ? typeof optionsCommands === "function" ? optionsCommands(genericCommandsFromRules) : optionsCommands : genericCommandsFromRules;
1606
+ if (!customElements.get("dn-commands-table")) {
1607
+ customElements.define("dn-commands-table", CommandsTable);
1608
+ }
1609
+ const commandsElement = document.createElement("dn-commands-table");
1610
+ if (commandOptions == null ? void 0 : commandOptions.title) {
1611
+ commandsElement.setAttribute("title", commandOptions.title);
1612
+ }
1613
+ commandsElement.commands = commands;
1614
+ if (commandOptions.columns) {
1615
+ commandsElement.columns = commandOptions.columns;
1616
+ }
1617
+ root.appendChild(commandsElement);
1618
+ return commandsElement;
1619
+ };
1620
+ renderer.getGenericCommandsFromNavRules = getGenericCommandsFromNavRules;
1621
+ renderer.CommandsTable = CommandsTable;
1420
1622
  return renderer;
1421
1623
  };
1422
1624
 
@@ -1506,9 +1708,7 @@ var fuzzyMatch = (input, candidates, labels = {}) => {
1506
1708
  const exactName = candidates.find((c) => c.toLowerCase() === lower);
1507
1709
  if (exactName)
1508
1710
  return { match: exactName, ambiguous: [] };
1509
- const exactLabel = candidates.find(
1510
- (c) => labels[c] && labels[c].toLowerCase() === lower
1511
- );
1711
+ const exactLabel = candidates.find((c) => labels[c] && labels[c].toLowerCase() === lower);
1512
1712
  if (exactLabel)
1513
1713
  return { match: exactLabel, ambiguous: [] };
1514
1714
  const namePrefix = candidates.filter((c) => c.toLowerCase().startsWith(lower));
@@ -1768,8 +1968,12 @@ var text_chat_default = (options) => {
1768
1968
  }
1769
1969
  });
1770
1970
  if (llm) {
1771
- addSystemMessage('Text navigation ready. Type "enter" to begin navigating, "help" for commands, or ask a question about the data.');
1772
- 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.');
1971
+ addSystemMessage(
1972
+ 'Text navigation ready. Type "enter" to begin navigating, "help" for commands, or ask a question about the data.'
1973
+ );
1974
+ addSystemMessage(
1975
+ '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.'
1976
+ );
1773
1977
  } else {
1774
1978
  addSystemMessage('Text navigation ready. Type "enter" to begin or "help" for available commands.');
1775
1979
  }
@@ -1838,9 +2042,7 @@ var text_chat_default = (options) => {
1838
2042
  const node = structure.nodes[currentNodeId];
1839
2043
  const available = getAvailableRules(currentNodeId, node, structure);
1840
2044
  const formatted = available.map((r) => formatRule(r, commandLabels));
1841
- addResponse(
1842
- `Available: ${formatted.join(", ")}, move to <search>.` + interactionSuffix + llmHint
1843
- );
2045
+ addResponse(`Available: ${formatted.join(", ")}, move to <search>.` + interactionSuffix + llmHint);
1844
2046
  }
1845
2047
  return;
1846
2048
  }
@@ -1854,9 +2056,7 @@ var text_chat_default = (options) => {
1854
2056
  onClick(node);
1855
2057
  addResponse(`Clicked: ${describeNode2(node)}`);
1856
2058
  } else {
1857
- addResponse(
1858
- onClick ? "Nothing to click here." : "Click interaction is not enabled for this chart."
1859
- );
2059
+ addResponse(onClick ? "Nothing to click here." : "Click interaction is not enabled for this chart.");
1860
2060
  }
1861
2061
  return;
1862
2062
  }
@@ -1909,7 +2109,9 @@ var text_chat_default = (options) => {
1909
2109
  return;
1910
2110
  }
1911
2111
  const llmHint = llm ? " Enter an API key above to ask questions about the data." : "";
1912
- addResponse('Type "enter" to begin navigating the structure, or "move to <search>" to jump to a node.' + llmHint);
2112
+ addResponse(
2113
+ 'Type "enter" to begin navigating the structure, or "move to <search>" to jump to a node.' + llmHint
2114
+ );
1913
2115
  return;
1914
2116
  }
1915
2117
  const allRules = getAllRuleNames(structure);
@@ -1973,5 +2175,201 @@ var text_chat_default = (options) => {
1973
2175
  };
1974
2176
  };
1975
2177
 
2178
+ // src/geometry.ts
2179
+ function grahamScan(points) {
2180
+ if (points.length < 3)
2181
+ return [...points];
2182
+ let pivot = points[0];
2183
+ for (const p of points) {
2184
+ if (p.y < pivot.y || p.y === pivot.y && p.x < pivot.x)
2185
+ pivot = p;
2186
+ }
2187
+ const sorted = [...points].sort((a, b) => {
2188
+ const ax = a.x - pivot.x, ay = a.y - pivot.y;
2189
+ const bx = b.x - pivot.x, by = b.y - pivot.y;
2190
+ const cross2 = ax * by - ay * bx;
2191
+ if (cross2 !== 0)
2192
+ return -cross2;
2193
+ return ax * ax + ay * ay - (bx * bx + by * by);
2194
+ });
2195
+ const hull = [];
2196
+ for (const p of sorted) {
2197
+ while (hull.length >= 2 && cross(hull[hull.length - 2], hull[hull.length - 1], p) <= 0) {
2198
+ hull.pop();
2199
+ }
2200
+ hull.push(p);
2201
+ }
2202
+ return hull;
2203
+ }
2204
+ function cross(O, A, B) {
2205
+ return (A.x - O.x) * (B.y - O.y) - (A.y - O.y) * (B.x - O.x);
2206
+ }
2207
+ function convexHullPath(points) {
2208
+ if (points.length === 0)
2209
+ return "";
2210
+ if (points.length === 1) {
2211
+ const p = points[0];
2212
+ return `M${p.x},${p.y}Z`;
2213
+ }
2214
+ const hull = grahamScan(points);
2215
+ if (hull.length === 0)
2216
+ return "";
2217
+ const [first, ...rest] = hull;
2218
+ return `M${fmt(first.x)},${fmt(first.y)}` + rest.map((p) => `L${fmt(p.x)},${fmt(p.y)}`).join("") + "Z";
2219
+ }
2220
+ function expandHull(hullPoints, padPx) {
2221
+ if (padPx === 0 || hullPoints.length === 0)
2222
+ return hullPoints;
2223
+ const cx = hullPoints.reduce((s, p) => s + p.x, 0) / hullPoints.length;
2224
+ const cy = hullPoints.reduce((s, p) => s + p.y, 0) / hullPoints.length;
2225
+ return hullPoints.map((p) => {
2226
+ const dx = p.x - cx;
2227
+ const dy = p.y - cy;
2228
+ const dist = Math.hypot(dx, dy);
2229
+ if (dist === 0)
2230
+ return p;
2231
+ return { x: p.x + dx / dist * padPx, y: p.y + dy / dist * padPx };
2232
+ });
2233
+ }
2234
+ function rectCorners(r) {
2235
+ return [
2236
+ { x: r.x, y: r.y },
2237
+ { x: r.x + r.width, y: r.y },
2238
+ { x: r.x + r.width, y: r.y + r.height },
2239
+ { x: r.x, y: r.y + r.height }
2240
+ ];
2241
+ }
2242
+ function padRect(r, pad) {
2243
+ return { x: r.x - pad, y: r.y - pad, width: r.width + pad * 2, height: r.height + pad * 2 };
2244
+ }
2245
+ function convexHullOfRects(rects, padPx = 0) {
2246
+ if (rects.length === 0)
2247
+ return "";
2248
+ const corners = rects.flatMap(rectCorners);
2249
+ const hull = grahamScan(corners);
2250
+ const expanded = padPx > 0 ? expandHull(hull, padPx) : hull;
2251
+ return hullToPath(expanded);
2252
+ }
2253
+ function unionOfRectPaths(rects, padPx = 0) {
2254
+ if (rects.length === 0)
2255
+ return "";
2256
+ return rects.map((r) => {
2257
+ const pr = padPx > 0 ? padRect(r, padPx) : r;
2258
+ const { x, y, width: w, height: h } = pr;
2259
+ return `M${fmt(x)},${fmt(y)}L${fmt(x + w)},${fmt(y)}L${fmt(x + w)},${fmt(y + h)}L${fmt(x)},${fmt(y + h)}Z`;
2260
+ }).join("");
2261
+ }
2262
+ function boundingRectPath(rects, padPx = 0) {
2263
+ if (rects.length === 0)
2264
+ return "";
2265
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
2266
+ for (const r of rects) {
2267
+ minX = Math.min(minX, r.x);
2268
+ minY = Math.min(minY, r.y);
2269
+ maxX = Math.max(maxX, r.x + r.width);
2270
+ maxY = Math.max(maxY, r.y + r.height);
2271
+ }
2272
+ minX -= padPx;
2273
+ minY -= padPx;
2274
+ maxX += padPx;
2275
+ maxY += padPx;
2276
+ return `M${fmt(minX)},${fmt(minY)}L${fmt(maxX)},${fmt(minY)}L${fmt(maxX)},${fmt(maxY)}L${fmt(minX)},${fmt(maxY)}Z`;
2277
+ }
2278
+ function convexHullOfCircles(circles, padPx = 0) {
2279
+ if (circles.length === 0)
2280
+ return "";
2281
+ const SAMPLES = 16;
2282
+ const points = [];
2283
+ for (const { x, y, r } of circles) {
2284
+ const effectiveR = r + padPx;
2285
+ for (let i = 0; i < SAMPLES; i++) {
2286
+ const angle = 2 * Math.PI * i / SAMPLES;
2287
+ points.push({
2288
+ x: x + effectiveR * Math.cos(angle),
2289
+ y: y + effectiveR * Math.sin(angle)
2290
+ });
2291
+ }
2292
+ }
2293
+ return convexHullPath(points);
2294
+ }
2295
+ function offsetLinePath(points, offsetPx) {
2296
+ if (points.length < 2) {
2297
+ if (points.length === 1) {
2298
+ const p = points[0];
2299
+ return convexHullOfCircles([{ x: p.x, y: p.y, r: offsetPx }]);
2300
+ }
2301
+ return "";
2302
+ }
2303
+ const normals = [];
2304
+ for (let i = 0; i < points.length - 1; i++) {
2305
+ const dx = points[i + 1].x - points[i].x;
2306
+ const dy = points[i + 1].y - points[i].y;
2307
+ const len = Math.hypot(dx, dy);
2308
+ normals.push(len === 0 ? { x: 0, y: -1 } : { x: -dy / len, y: dx / len });
2309
+ }
2310
+ const vertexNormals = [];
2311
+ for (let i = 0; i < points.length; i++) {
2312
+ if (i === 0) {
2313
+ vertexNormals.push(normals[0]);
2314
+ } else if (i === points.length - 1) {
2315
+ vertexNormals.push(normals[normals.length - 1]);
2316
+ } else {
2317
+ const n1 = normals[i - 1];
2318
+ const n2 = normals[i];
2319
+ const avg = { x: (n1.x + n2.x) / 2, y: (n1.y + n2.y) / 2 };
2320
+ const len = Math.hypot(avg.x, avg.y);
2321
+ vertexNormals.push(len === 0 ? n1 : { x: avg.x / len, y: avg.y / len });
2322
+ }
2323
+ }
2324
+ const left = points.map((p, i) => ({
2325
+ x: p.x + vertexNormals[i].x * offsetPx,
2326
+ y: p.y + vertexNormals[i].y * offsetPx
2327
+ }));
2328
+ const right = points.map((p, i) => ({
2329
+ x: p.x - vertexNormals[i].x * offsetPx,
2330
+ y: p.y - vertexNormals[i].y * offsetPx
2331
+ })).reverse();
2332
+ const firstLeft = left[0];
2333
+ let d = `M${fmt(firstLeft.x)},${fmt(firstLeft.y)}`;
2334
+ for (let i = 1; i < left.length; i++) {
2335
+ d += `L${fmt(left[i].x)},${fmt(left[i].y)}`;
2336
+ }
2337
+ const lastLeft = left[left.length - 1];
2338
+ const firstRight = right[0];
2339
+ d += arcCap(lastLeft, firstRight, offsetPx);
2340
+ for (let i = 1; i < right.length; i++) {
2341
+ d += `L${fmt(right[i].x)},${fmt(right[i].y)}`;
2342
+ }
2343
+ const lastRight = right[right.length - 1];
2344
+ d += arcCap(lastRight, firstLeft, offsetPx);
2345
+ d += "Z";
2346
+ return d;
2347
+ }
2348
+ function arcCap(from, to, r) {
2349
+ return `A${fmt(r)},${fmt(r)},0,0,0,${fmt(to.x)},${fmt(to.y)}`;
2350
+ }
2351
+ function fmt(n) {
2352
+ return Math.round(n * 100) / 100 + "";
2353
+ }
2354
+ function hullToPath(hull) {
2355
+ if (hull.length === 0)
2356
+ return "";
2357
+ const [first, ...rest] = hull;
2358
+ return `M${fmt(first.x)},${fmt(first.y)}` + rest.map((p) => `L${fmt(p.x)},${fmt(p.y)}`).join("") + "Z";
2359
+ }
2360
+
1976
2361
  // src/index.ts
1977
2362
  var src_default = { structure: structure_default, input: input_default, rendering: rendering_default, textChat: text_chat_default };
2363
+ // Annotate the CommonJS export names for ESM import in node:
2364
+ 0 && (module.exports = {
2365
+ boundingRectPath,
2366
+ convexHullOfCircles,
2367
+ convexHullOfRects,
2368
+ convexHullPath,
2369
+ createValidId,
2370
+ describeNode,
2371
+ expandHull,
2372
+ grahamScan,
2373
+ offsetLinePath,
2374
+ unionOfRectPaths
2375
+ });